summaryrefslogtreecommitdiff
path: root/libs/temporal
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2017-09-24 10:47:28 -0400
committerPaul Davis <paul@linuxaudiosystems.com>2017-09-24 10:47:28 -0400
commitb62c305f200351b2cbae70de8327fa235ff515dc (patch)
tree10d724d8e6db552fbc66863a0500e0de4ee1ffef /libs/temporal
parent8890494ba31b007b1b138f5e7ebdb35f192a0cfd (diff)
change libtimecode to libtemporal, add Evoral::Beats, positional types and superclock headers
Diffstat (limited to 'libs/temporal')
-rw-r--r--libs/temporal/MSVCtimecode/timecode.vcproj300
-rw-r--r--libs/temporal/bbt_time.cc50
-rw-r--r--libs/temporal/temporal/bbt_time.h142
-rw-r--r--libs/temporal/temporal/beats.h326
-rw-r--r--libs/temporal/temporal/superclock.h36
-rw-r--r--libs/temporal/temporal/time.h148
-rw-r--r--libs/temporal/temporal/types.h46
-rw-r--r--libs/temporal/temporal/visibility.h40
-rw-r--r--libs/temporal/time.cc853
-rw-r--r--libs/temporal/types.h46
-rw-r--r--libs/temporal/wscript29
11 files changed, 2016 insertions, 0 deletions
diff --git a/libs/temporal/MSVCtimecode/timecode.vcproj b/libs/temporal/MSVCtimecode/timecode.vcproj
new file mode 100644
index 0000000000..24c4aeb2c3
--- /dev/null
+++ b/libs/temporal/MSVCtimecode/timecode.vcproj
@@ -0,0 +1,300 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="timecode"
+ ProjectGUID="{33DE1DDA-3995-4650-AF94-36971FF0E6F9}"
+ RootNamespace="timecode"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug 32|Win32"
+ OutputDirectory="$(ProjectDir)\$(ConfigurationName)\lib"
+ IntermediateDirectory="$(ProjectDir)\$(ConfigurationName)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="..\..\..\MSVCMixbus3\MSVCMixbus3.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/FI$(TargetSxsFolder)\targetsxs.h"
+ Optimization="0"
+ AdditionalIncludeDirectories="..;..\..\ardour;..\..\pbd;..\..\fst;&quot;$(GenericIncludeFolder)\ardourext&quot;;..\..\surfaces\control_protocol;..\..\evoral;..\..\libltc;..\..\rubberband;&quot;..\..\vamp-sdk&quot;;&quot;..\..\midi++2&quot;;..\..\taglib;..\..\taglib\taglib;..\..\taglib\taglib\toolkit;..\..\audiographer;&quot;$(GenericLibraryFolder)\glib-2.0\include&quot;;&quot;$(GenericIncludeFolder)\glibmm&quot;;&quot;$(GenericIncludeFolder)\libsndfile&quot;;&quot;$(GenericIncludeFolder)\gtk-2.0&quot;;&quot;$(GenericIncludeFolder)\cairo&quot;;&quot;$(GenericIncludeFolder)\pango-1.0&quot;;&quot;$(GenericIncludeFolder)\gtk-2.0\gdk&quot;;&quot;$(GenericIncludeFolder)\atk-2.0&quot;;&quot;$(GenericIncludeFolder)\lrdf&quot;;&quot;$(GenericIncludeFolder)\raptor&quot;;&quot;$(GenericIncludeFolder)\lilv-0&quot;;&quot;$(GenericIncludeFolder)\suil-0&quot;;&quot;$(GenericIncludeFolder)\serd-0&quot;;&quot;$(GenericIncludeFolder)\sord-0&quot;;&quot;$(GenericIncludeFolder)\lv2&quot;;&quot;$(GenericIncludeFolder)\sratom-0&quot;"
+ PreprocessorDefinitions="PLATFORM_WINDOWS;COMPILER_MSVC;UINTSDEFINED=1;BUILDING_TIMECODE;RUBBERBAND_IS_IN_WIN_STATIC_LIB;LUA_BUILD_AS_DLL;USE_CAIRO_IMAGE_SURFACE;NOMINMAX;NO_POSIX_MEMALIGN;LIBTIMECODE_DLL_EXPORTS;INCLUDE_ARDOUR_MISCELLANEOUS=1;BOOST_REGEX_DYN_LINK;BOOST_REGEX_NO_LIB;BOOST_CHRONO_NO_LIB;BOOST_SYSTEM_NO_LIB;BOOST_THREAD_NO_LIB;BOOST_DATE_TIME_NO_LIB;GNU_WIN32;WIN32;_WIN32;_DEBUG;DEBUG=&quot;Debug&quot;;ARCH_X86;USE_XMMINTRIN;BUILD_SSE_OPTIMIZATIONS;ENABLE_NLS;PACKAGE=&quot;\&quot;ardour3_timecode\&quot;&quot;;PROGRAM_NAME=&quot;\&quot;Mixbus3\&quot;&quot;;_REENTRANT;_USE_MATH_DEFINES;_LARGEFILE_SOURCE;_LARGEFILE64_SOURCE;LIBC_DISABLE_DEPRECATED;BOOST_SYSTEM_NO_DEPRECATED;__STDC_LIMIT_MACROS;__STDC_FORMAT_MACROS;INTERNAL_SHARED_LIBS=1;JACK_SESSION=1;HAVE_GLIB=1;HAVE_GTHREAD=1;HAVE_SNDFILE=1;HAVE_GIOMM=1;HAVE_CURL=1;HAVE_LO=1;HAVE_MODE_T=1;PHONE_HOME=1;FREESOUND=1;WINDOWS_KEY=\&quot;Mod4&gt;&lt;Super\&quot;;IS_OSX=0;HAVE_XML=1;HAVE_UUID=1;HAVE_LIBS_PBD=1;HAVE_JACK=1;HAVE_LIBS_MIDIPP2=1;HAVE_LIBS_EVORAL=1;HAVE_FFTW3=1;HAVE_FFTW3F=1;HAVE_AUBIO=1;HAVE_LIBS_VAMP_SDK=1;HAVE_LIBS_VAMP_PLUGINS=1;HAVE_LIBS_TAGLIB=1;HAVE_LIBS_LIBLTC=1;HAVE_LIBS_RUBBERBAND=1;HAVE_CONTROL_PROTOCOL=1;HAVE_FRONTIER=1;HAVE_GENERIC_MIDI=1;HAVE_MACKIE=1;HAVE_OSC=1;HAVE_TRANZPORT=1;HAVE_WIIMOTE=1;HAVE_LIBS_SURFACES=1;HAVE_2IN2OUT=1;HAVE_1IN2OUT=1;HAVE_VBAP=1;HAVE_LIBS_PANNERS=1;HAVE_LIBS_TIMECODE=1;HAVE_LRDF=1;HAVE_SAMPLERATE=1;HAVE_SERD=1;HAVE_SORD=1;HAVE_SRATOM=1;HAVE_LILV=1;HAVE_LILV_0_16_0=1;HAVE_OGG=1;HAVE_FLAC=1;HAVE_RUBBERBAND=1;USE_RUBBERBAND=1;HAVE_JACK_SESSION=1;HAVE_UNISTD=1;HAVE_JACK_ON_INFO_SHUTDOWN=1;HAVE_JACK_VIDEO_SUPPORT=1;HAVE_BOOST_SCOPED_PTR_HPP=1;HAVE_BOOST_PTR_CONTAINER_PTR_LIST_HPP=1;HAVE_LIBS_ARDOUR=1;HAVE_GTKMM=1;HAVE_GTK=1;HAVE_LIBS_GTKMM2EXT=1;HAVE_LIBS_CLEARLOOKS_NEWER=1;HAVE_BOOST_FORMAT_HPP=1;HAVE_LIBS_AUDIOGRAPHER=1;HAVE_GNOMECANVAS=0;HAVE_GNOMECANVASMM=0;HAVE_X11=0;HAVE_FONTCONFIG=1;HAVE_BOOST_SHARED_PTR_HPP=1;HAVE_BOOST_WEAK_PTR_HPP=1;HAVE_GTK2_ARDOUR=1;HAVE_EXPORT=1;HAVE_MIDI_MAPS=1;HAVE_MCP=1;HAVE_PATCHFILES=1;HAVE_TOOLS_SANITY_CHECK=1;SMF_VERSION=\&quot;1.2\&quot;;CURRENT_SESSION_FILE_VERSION=3002"
+ MinimalRebuild="true"
+ RuntimeLibrary="3"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ CompileAs="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="$(DllPrefix)pbd32D.lib"
+ OutputFile="$(OutDir)\$(DllPrefix)$(ProjectName)32D.dll"
+ AdditionalLibraryDirectories="F:\pthread-win32\Pre-built.2\lib"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="copy /Y &quot;$(OutDir)\$(TargetName).dll&quot; &quot;$(Debug32TargetFolder)\$(TargetName).dll&quot;&#x0D;&#x0A;copy /Y &quot;$(OutDir)\$(TargetName).dll&quot; &quot;$(Debug32TestSuiteFolder)\$(TargetName).dll&quot;&#x0D;&#x0A;copy /Y &quot;$(OutDir)\$(TargetName).lib&quot; &quot;$(GenericWin32LibraryFolder)\$(TargetName).lib&quot;&#x0D;&#x0A;"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release 32|Win32"
+ OutputDirectory="$(ProjectDir)\$(ConfigurationName)\lib"
+ IntermediateDirectory="$(ProjectDir)\$(ConfigurationName)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="..\..\..\MSVCMixbus3\MSVCMixbus3.vsprops"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/FI$(TargetSxsFolder)\targetsxs.h"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..;..\..\ardour;..\..\pbd;..\..\fst;&quot;$(GenericIncludeFolder)\ardourext&quot;;..\..\surfaces\control_protocol;..\..\evoral;..\..\libltc;..\..\rubberband;&quot;..\..\vamp-sdk&quot;;&quot;..\..\midi++2&quot;;..\..\taglib;..\..\taglib\taglib;..\..\taglib\taglib\toolkit;..\..\audiographer;&quot;$(GenericLibraryFolder)\glib-2.0\include&quot;;&quot;$(GenericIncludeFolder)\glibmm&quot;;&quot;$(GenericIncludeFolder)\libsndfile&quot;;&quot;$(GenericIncludeFolder)\gtk-2.0&quot;;&quot;$(GenericIncludeFolder)\cairo&quot;;&quot;$(GenericIncludeFolder)\pango-1.0&quot;;&quot;$(GenericIncludeFolder)\gtk-2.0\gdk&quot;;&quot;$(GenericIncludeFolder)\atk-2.0&quot;;&quot;$(GenericIncludeFolder)\lrdf&quot;;&quot;$(GenericIncludeFolder)\raptor&quot;;&quot;$(GenericIncludeFolder)\lilv-0&quot;;&quot;$(GenericIncludeFolder)\suil-0&quot;;&quot;$(GenericIncludeFolder)\serd-0&quot;;&quot;$(GenericIncludeFolder)\sord-0&quot;;&quot;$(GenericIncludeFolder)\lv2&quot;;&quot;$(GenericIncludeFolder)\sratom-0&quot;"
+ PreprocessorDefinitions="PLATFORM_WINDOWS;COMPILER_MSVC;UINTSDEFINED=1;_SECURE_SCL=0;BUILDING_TIMECODE;RUBBERBAND_IS_IN_WIN_STATIC_LIB;LUA_BUILD_AS_DLL;USE_CAIRO_IMAGE_SURFACE;NOMINMAX;NO_POSIX_MEMALIGN;LIBTIMECODE_DLL_EXPORTS;INCLUDE_ARDOUR_MISCELLANEOUS=1;BOOST_REGEX_DYN_LINK;BOOST_REGEX_NO_LIB;BOOST_CHRONO_NO_LIB;BOOST_SYSTEM_NO_LIB;BOOST_THREAD_NO_LIB;BOOST_DATE_TIME_NO_LIB;GNU_WIN32;WIN32;_WIN32;NDEBUG;ARCH_X86;USE_XMMINTRIN;BUILD_SSE_OPTIMIZATIONS;ENABLE_NLS;PACKAGE=&quot;\&quot;ardour3_timecode\&quot;&quot;;PROGRAM_NAME=&quot;\&quot;Mixbus3\&quot;&quot;;_REENTRANT;_USE_MATH_DEFINES;_LARGEFILE_SOURCE;_LARGEFILE64_SOURCE;LIBC_DISABLE_DEPRECATED;BOOST_SYSTEM_NO_DEPRECATED;__STDC_LIMIT_MACROS;__STDC_FORMAT_MACROS;INTERNAL_SHARED_LIBS=1;JACK_SESSION=1;HAVE_GLIB=1;HAVE_GTHREAD=1;HAVE_SNDFILE=1;HAVE_GIOMM=1;HAVE_CURL=1;HAVE_LO=1;HAVE_MODE_T=1;PHONE_HOME=1;FREESOUND=1;WINDOWS_KEY=\&quot;Mod4&gt;&lt;Super\&quot;;IS_OSX=0;HAVE_XML=1;HAVE_UUID=1;HAVE_LIBS_PBD=1;HAVE_JACK=1;HAVE_LIBS_MIDIPP2=1;HAVE_LIBS_EVORAL=1;HAVE_FFTW3=1;HAVE_FFTW3F=1;HAVE_AUBIO=1;HAVE_LIBS_VAMP_SDK=1;HAVE_LIBS_VAMP_PLUGINS=1;HAVE_LIBS_TAGLIB=1;HAVE_LIBS_LIBLTC=1;HAVE_LIBS_RUBBERBAND=1;HAVE_CONTROL_PROTOCOL=1;HAVE_FRONTIER=1;HAVE_GENERIC_MIDI=1;HAVE_MACKIE=1;HAVE_OSC=1;HAVE_TRANZPORT=1;HAVE_WIIMOTE=1;HAVE_LIBS_SURFACES=1;HAVE_2IN2OUT=1;HAVE_1IN2OUT=1;HAVE_VBAP=1;HAVE_LIBS_PANNERS=1;HAVE_LIBS_TIMECODE=1;HAVE_LRDF=1;HAVE_SAMPLERATE=1;HAVE_SERD=1;HAVE_SORD=1;HAVE_SRATOM=1;HAVE_LILV=1;HAVE_LILV_0_16_0=1;HAVE_OGG=1;HAVE_FLAC=1;HAVE_RUBBERBAND=1;USE_RUBBERBAND=1;HAVE_JACK_SESSION=1;HAVE_UNISTD=1;HAVE_JACK_ON_INFO_SHUTDOWN=1;HAVE_JACK_VIDEO_SUPPORT=1;HAVE_BOOST_SCOPED_PTR_HPP=1;HAVE_BOOST_PTR_CONTAINER_PTR_LIST_HPP=1;HAVE_LIBS_ARDOUR=1;HAVE_GTKMM=1;HAVE_GTK=1;HAVE_LIBS_GTKMM2EXT=1;HAVE_LIBS_CLEARLOOKS_NEWER=1;HAVE_BOOST_FORMAT_HPP=1;HAVE_LIBS_AUDIOGRAPHER=1;HAVE_GNOMECANVAS=0;HAVE_GNOMECANVASMM=0;HAVE_X11=0;HAVE_FONTCONFIG=1;HAVE_BOOST_SHARED_PTR_HPP=1;HAVE_BOOST_WEAK_PTR_HPP=1;HAVE_GTK2_ARDOUR=1;HAVE_EXPORT=1;HAVE_MIDI_MAPS=1;HAVE_MCP=1;HAVE_PATCHFILES=1;HAVE_TOOLS_SANITY_CHECK=1;SMF_VERSION=\&quot;1.2\&quot;;CURRENT_SESSION_FILE_VERSION=3002"
+ StringPooling="false"
+ RuntimeLibrary="2"
+ EnableEnhancedInstructionSet="1"
+ WarningLevel="3"
+ CompileAs="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="$(DllPrefix)pbd32.lib"
+ OutputFile="$(OutDir)\$(DllPrefix)$(ProjectName)32.dll"
+ AdditionalLibraryDirectories="F:\pthread-win32\Pre-built.2\lib"
+ SubSystem="2"
+ OptimizeReferences="2"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="copy /Y &quot;$(OutDir)\$(TargetName).dll&quot; &quot;$(Release32TargetFolder)\$(TargetName).dll&quot;&#x0D;&#x0A;copy /Y &quot;$(OutDir)\$(TargetName).dll&quot; &quot;$(Release32TestSuiteFolder)\$(TargetName).dll&quot;&#x0D;&#x0A;copy /Y &quot;$(OutDir)\$(TargetName).lib&quot; &quot;$(GenericWin32LibraryFolder)\$(TargetName).lib&quot;&#x0D;&#x0A;"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release 32 with Debugging Capability|Win32"
+ OutputDirectory="$(ProjectDir)\$(ConfigurationName)\lib"
+ IntermediateDirectory="$(ProjectDir)\$(ConfigurationName)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="..\..\..\MSVCMixbus3\MSVCMixbus3.vsprops"
+ CharacterSet="2"
+ WholeProgramOptimization="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/FI$(TargetSxsFolder)\targetsxs.h"
+ Optimization="0"
+ AdditionalIncludeDirectories="..;..\..\ardour;..\..\pbd;..\..\fst;&quot;$(GenericIncludeFolder)\ardourext&quot;;..\..\surfaces\control_protocol;..\..\evoral;..\..\libltc;..\..\rubberband;&quot;..\..\vamp-sdk&quot;;&quot;..\..\midi++2&quot;;..\..\taglib;..\..\taglib\taglib;..\..\taglib\taglib\toolkit;..\..\audiographer;&quot;$(GenericLibraryFolder)\glib-2.0\include&quot;;&quot;$(GenericIncludeFolder)\glibmm&quot;;&quot;$(GenericIncludeFolder)\libsndfile&quot;;&quot;$(GenericIncludeFolder)\gtk-2.0&quot;;&quot;$(GenericIncludeFolder)\cairo&quot;;&quot;$(GenericIncludeFolder)\pango-1.0&quot;;&quot;$(GenericIncludeFolder)\gtk-2.0\gdk&quot;;&quot;$(GenericIncludeFolder)\atk-2.0&quot;;&quot;$(GenericIncludeFolder)\lrdf&quot;;&quot;$(GenericIncludeFolder)\raptor&quot;;&quot;$(GenericIncludeFolder)\lilv-0&quot;;&quot;$(GenericIncludeFolder)\suil-0&quot;;&quot;$(GenericIncludeFolder)\serd-0&quot;;&quot;$(GenericIncludeFolder)\sord-0&quot;;&quot;$(GenericIncludeFolder)\lv2&quot;;&quot;$(GenericIncludeFolder)\sratom-0&quot;"
+ PreprocessorDefinitions="PLATFORM_WINDOWS;COMPILER_MSVC;UINTSDEFINED=1;_SECURE_SCL=0;BUILDING_TIMECODE;RUBBERBAND_IS_IN_WIN_STATIC_LIB;LUA_BUILD_AS_DLL;USE_CAIRO_IMAGE_SURFACE;NOMINMAX;NO_POSIX_MEMALIGN;LIBTIMECODE_DLL_EXPORTS;INCLUDE_ARDOUR_MISCELLANEOUS=1;BOOST_REGEX_DYN_LINK;BOOST_REGEX_NO_LIB;BOOST_CHRONO_NO_LIB;BOOST_SYSTEM_NO_LIB;BOOST_THREAD_NO_LIB;BOOST_DATE_TIME_NO_LIB;GNU_WIN32;WIN32;_WIN32;ARCH_X86;USE_XMMINTRIN;BUILD_SSE_OPTIMIZATIONS;ENABLE_NLS;PACKAGE=&quot;\&quot;ardour3_timecode\&quot;&quot;;PROGRAM_NAME=&quot;\&quot;Mixbus3\&quot;&quot;;_REENTRANT;_USE_MATH_DEFINES;_LARGEFILE_SOURCE;_LARGEFILE64_SOURCE;LIBC_DISABLE_DEPRECATED;BOOST_SYSTEM_NO_DEPRECATED;__STDC_LIMIT_MACROS;__STDC_FORMAT_MACROS;INTERNAL_SHARED_LIBS=1;JACK_SESSION=1;HAVE_GLIB=1;HAVE_GTHREAD=1;HAVE_SNDFILE=1;HAVE_GIOMM=1;HAVE_CURL=1;HAVE_LO=1;HAVE_MODE_T=1;PHONE_HOME=1;FREESOUND=1;WINDOWS_KEY=\&quot;Mod4&gt;&lt;Super\&quot;;IS_OSX=0;HAVE_XML=1;HAVE_UUID=1;HAVE_LIBS_PBD=1;HAVE_JACK=1;HAVE_LIBS_MIDIPP2=1;HAVE_LIBS_EVORAL=1;HAVE_FFTW3=1;HAVE_FFTW3F=1;HAVE_AUBIO=1;HAVE_LIBS_VAMP_SDK=1;HAVE_LIBS_VAMP_PLUGINS=1;HAVE_LIBS_TAGLIB=1;HAVE_LIBS_LIBLTC=1;HAVE_LIBS_RUBBERBAND=1;HAVE_CONTROL_PROTOCOL=1;HAVE_FRONTIER=1;HAVE_GENERIC_MIDI=1;HAVE_MACKIE=1;HAVE_OSC=1;HAVE_TRANZPORT=1;HAVE_WIIMOTE=1;HAVE_LIBS_SURFACES=1;HAVE_2IN2OUT=1;HAVE_1IN2OUT=1;HAVE_VBAP=1;HAVE_LIBS_PANNERS=1;HAVE_LIBS_TIMECODE=1;HAVE_LRDF=1;HAVE_SAMPLERATE=1;HAVE_SERD=1;HAVE_SORD=1;HAVE_SRATOM=1;HAVE_LILV=1;HAVE_LILV_0_16_0=1;HAVE_OGG=1;HAVE_FLAC=1;HAVE_RUBBERBAND=1;USE_RUBBERBAND=1;HAVE_JACK_SESSION=1;HAVE_UNISTD=1;HAVE_JACK_ON_INFO_SHUTDOWN=1;HAVE_JACK_VIDEO_SUPPORT=1;HAVE_BOOST_SCOPED_PTR_HPP=1;HAVE_BOOST_PTR_CONTAINER_PTR_LIST_HPP=1;HAVE_LIBS_ARDOUR=1;HAVE_GTKMM=1;HAVE_GTK=1;HAVE_LIBS_GTKMM2EXT=1;HAVE_LIBS_CLEARLOOKS_NEWER=1;HAVE_BOOST_FORMAT_HPP=1;HAVE_LIBS_AUDIOGRAPHER=1;HAVE_GNOMECANVAS=0;HAVE_GNOMECANVASMM=0;HAVE_X11=0;HAVE_FONTCONFIG=1;HAVE_BOOST_SHARED_PTR_HPP=1;HAVE_BOOST_WEAK_PTR_HPP=1;HAVE_GTK2_ARDOUR=1;HAVE_EXPORT=1;HAVE_MIDI_MAPS=1;HAVE_MCP=1;HAVE_PATCHFILES=1;HAVE_TOOLS_SANITY_CHECK=1;SMF_VERSION=\&quot;1.2\&quot;;CURRENT_SESSION_FILE_VERSION=3002"
+ StringPooling="false"
+ RuntimeLibrary="2"
+ EnableEnhancedInstructionSet="1"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ CompileAs="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="$(DllPrefix)pbd32RDC.lib"
+ OutputFile="$(OutDir)\$(DllPrefix)$(ProjectName)32RDC.dll"
+ AdditionalLibraryDirectories="F:\pthread-win32\Pre-built.2\lib"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="copy /Y &quot;$(OutDir)\$(TargetName).dll&quot; &quot;$(Release32TestSuiteFolder)\$(TargetName).dll&quot;&#x0D;&#x0A;copy /Y &quot;$(OutDir)\$(TargetName).lib&quot; &quot;$(GenericWin32LibraryFolder)\$(TargetName).lib&quot;&#x0D;&#x0A;"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\src\bbt_time.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\src\time.cc"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\timecode\bbt_time.h"
+ >
+ </File>
+ <File
+ RelativePath="..\timecode\time.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath="..\..\..\gtk2_ardour\win32\msvc_resources.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/libs/temporal/bbt_time.cc b/libs/temporal/bbt_time.cc
new file mode 100644
index 0000000000..8ee6d1a313
--- /dev/null
+++ b/libs/temporal/bbt_time.cc
@@ -0,0 +1,50 @@
+/*
+ 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.
+*/
+
+#include <cmath>
+#include <cassert>
+
+#include "timecode/bbt_time.h"
+
+using namespace Timecode;
+
+/* This defines the smallest division of a "beat".
+
+ The number is intended to have as many integer factors as possible so that
+ 1/Nth divisions are integer numbers of ticks.
+
+ 1920 has many factors, though going up to 3840 gets a couple more.
+
+ This needs to match Evoral::Beats::PPQN
+*/
+
+const double BBT_Time::ticks_per_beat = 1920.0;
+
+BBT_Offset::BBT_Offset (double dbeats)
+{
+ /* NOTE: this does not construct a BBT time in a canonical form,
+ in that beats may be a very large number, and bars will
+ always be zero. Hence ... it's a BBT_Offset
+ */
+
+ assert (dbeats >= 0);
+
+ bars = 0;
+ beats = lrint (floor (dbeats));
+ ticks = lrint (floor (BBT_Time::ticks_per_beat * fmod (dbeats, 1.0)));
+}
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__ */
diff --git a/libs/temporal/time.cc b/libs/temporal/time.cc
new file mode 100644
index 0000000000..55fd636d3e
--- /dev/null
+++ b/libs/temporal/time.cc
@@ -0,0 +1,853 @@
+/*
+ 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 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.
+*/
+
+#define Timecode_IS_AROUND_ZERO(sm) (!(sm).frames && !(sm).seconds && !(sm).minutes && !(sm).hours)
+#define Timecode_IS_ZERO(sm) (!(sm).frames && !(sm).seconds && !(sm).minutes && !(sm).hours && !(sm.subframes))
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "timecode/time.h"
+
+namespace Timecode {
+
+double Time::default_rate = 30.0;
+
+
+/** Increment @a timecode by exactly one sample (keep subframes value).
+ * Realtime safe.
+ * @return true if seconds wrap.
+ */
+Wrap
+increment (Time& timecode, uint32_t subframes_per_frame)
+{
+ Wrap wrap = NONE;
+
+ if (timecode.negative) {
+ if (Timecode_IS_AROUND_ZERO (timecode) && timecode.subframes) {
+ // We have a zero transition involving only subframes
+ timecode.subframes = subframes_per_frame - timecode.subframes;
+ timecode.negative = false;
+ return SECONDS;
+ }
+
+ timecode.negative = false;
+ wrap = decrement (timecode, subframes_per_frame);
+ if (!Timecode_IS_ZERO (timecode)) {
+ timecode.negative = true;
+ }
+ return wrap;
+ }
+
+ switch ((int)ceil (timecode.rate)) {
+ case 24:
+ if (timecode.frames == 23) {
+ timecode.frames = 0;
+ wrap = SECONDS;
+ }
+ break;
+ case 25:
+ if (timecode.frames == 24) {
+ timecode.frames = 0;
+ wrap = SECONDS;
+ }
+ break;
+ case 30:
+ if (timecode.drop) {
+ if (timecode.frames == 29) {
+ if (((timecode.minutes + 1) % 10) && (timecode.seconds == 59)) {
+ timecode.frames = 2;
+ }
+ else {
+ timecode.frames = 0;
+ }
+ wrap = SECONDS;
+ }
+ } else {
+
+ if (timecode.frames == 29) {
+ timecode.frames = 0;
+ wrap = SECONDS;
+ }
+ }
+ break;
+ case 60:
+ if (timecode.frames == 59) {
+ timecode.frames = 0;
+ wrap = SECONDS;
+ }
+ break;
+ }
+
+ if (wrap == SECONDS) {
+ if (timecode.seconds == 59) {
+ timecode.seconds = 0;
+ wrap = MINUTES;
+ if (timecode.minutes == 59) {
+ timecode.minutes = 0;
+ wrap = HOURS;
+ timecode.hours++;
+ } else {
+ timecode.minutes++;
+ }
+ } else {
+ timecode.seconds++;
+ }
+ } else {
+ timecode.frames++;
+ }
+
+ return wrap;
+}
+
+
+/** Decrement @a timecode by exactly one sample (keep subframes value)
+ * Realtime safe.
+ * @return true if seconds wrap. */
+Wrap
+decrement (Time& timecode, uint32_t subframes_per_frame)
+{
+ Wrap wrap = NONE;
+
+ if (timecode.negative || Timecode_IS_ZERO (timecode)) {
+ timecode.negative = false;
+ wrap = increment (timecode, subframes_per_frame);
+ timecode.negative = true;
+ return wrap;
+ } else if (Timecode_IS_AROUND_ZERO (timecode) && timecode.subframes) {
+ // We have a zero transition involving only subframes
+ timecode.subframes = subframes_per_frame - timecode.subframes;
+ timecode.negative = true;
+ return SECONDS;
+ }
+
+ switch ((int)ceil (timecode.rate)) {
+ case 24:
+ if (timecode.frames == 0) {
+ timecode.frames = 23;
+ wrap = SECONDS;
+ }
+ break;
+ case 25:
+ if (timecode.frames == 0) {
+ timecode.frames = 24;
+ wrap = SECONDS;
+ }
+ break;
+ case 30:
+ if (timecode.drop) {
+ if ((timecode.minutes % 10) && (timecode.seconds == 0)) {
+ if (timecode.frames <= 2) {
+ timecode.frames = 29;
+ wrap = SECONDS;
+ }
+ } else if (timecode.frames == 0) {
+ timecode.frames = 29;
+ wrap = SECONDS;
+ }
+
+ } else {
+ if (timecode.frames == 0) {
+ timecode.frames = 29;
+ wrap = SECONDS;
+ }
+ }
+ break;
+ case 60:
+ if (timecode.frames == 0) {
+ timecode.frames = 59;
+ wrap = SECONDS;
+ }
+ break;
+ }
+
+ if (wrap == SECONDS) {
+ if (timecode.seconds == 0) {
+ timecode.seconds = 59;
+ wrap = MINUTES;
+ if (timecode.minutes == 0) {
+ timecode.minutes = 59;
+ wrap = HOURS;
+ timecode.hours--;
+ }
+ else {
+ timecode.minutes--;
+ }
+ } else {
+ timecode.seconds--;
+ }
+ } else {
+ timecode.frames--;
+ }
+
+ if (Timecode_IS_ZERO (timecode)) {
+ timecode.negative = false;
+ }
+
+ return wrap;
+}
+
+
+/** Go to lowest absolute subframe value in this sample (set to 0 :-)) */
+void
+frames_floot (Time& timecode)
+{
+ timecode.subframes = 0;
+ if (Timecode_IS_ZERO (timecode)) {
+ timecode.negative = false;
+ }
+}
+
+
+/** Increment @a timecode by one subframe */
+Wrap
+increment_subframes (Time& timecode, uint32_t subframes_per_frame)
+{
+ Wrap wrap = NONE;
+
+ if (timecode.negative) {
+ timecode.negative = false;
+ wrap = decrement_subframes (timecode, subframes_per_frame);
+ if (!Timecode_IS_ZERO (timecode)) {
+ timecode.negative = true;
+ }
+ return wrap;
+ }
+
+ timecode.subframes++;
+ if (timecode.subframes >= subframes_per_frame) {
+ timecode.subframes = 0;
+ increment (timecode, subframes_per_frame);
+ return FRAMES;
+ }
+ return NONE;
+}
+
+
+/** Decrement @a timecode by one subframe */
+Wrap
+decrement_subframes (Time& timecode, uint32_t subframes_per_frame)
+{
+ Wrap wrap = NONE;
+
+ if (timecode.negative) {
+ timecode.negative = false;
+ wrap = increment_subframes (timecode, subframes_per_frame);
+ timecode.negative = true;
+ return wrap;
+ }
+
+ if (timecode.subframes <= 0) {
+ timecode.subframes = 0;
+ if (Timecode_IS_ZERO (timecode)) {
+ timecode.negative = true;
+ timecode.subframes = 1;
+ return FRAMES;
+ } else {
+ decrement (timecode, subframes_per_frame);
+ timecode.subframes = 79;
+ return FRAMES;
+ }
+ } else {
+ timecode.subframes--;
+ if (Timecode_IS_ZERO (timecode)) {
+ timecode.negative = false;
+ }
+ return NONE;
+ }
+}
+
+
+/** Go to next whole second (frames == 0 or frames == 2) */
+Wrap
+increment_seconds (Time& timecode, uint32_t subframes_per_frame)
+{
+ Wrap wrap = NONE;
+
+ // Clear subframes
+ frames_floot (timecode);
+
+ if (timecode.negative) {
+ // Wrap second if on second boundary
+ wrap = increment (timecode, subframes_per_frame);
+ // Go to lowest absolute frame value
+ seconds_floor (timecode);
+ if (Timecode_IS_ZERO (timecode)) {
+ timecode.negative = false;
+ }
+ } else {
+ // Go to highest possible frame in this second
+ switch ((int)ceil (timecode.rate)) {
+ case 24:
+ timecode.frames = 23;
+ break;
+ case 25:
+ timecode.frames = 24;
+ break;
+ case 30:
+ timecode.frames = 29;
+ break;
+ case 60:
+ timecode.frames = 59;
+ break;
+ }
+
+ // Increment by one frame
+ wrap = increment (timecode, subframes_per_frame);
+ }
+
+ return wrap;
+}
+
+
+/** Go to lowest (absolute) frame value in this second
+ * Doesn't care about positive/negative */
+void
+seconds_floor (Time& timecode)
+{
+ // Clear subframes
+ frames_floot (timecode);
+
+ // Go to lowest possible frame in this second
+ switch ((int)ceil (timecode.rate)) {
+ case 24:
+ case 25:
+ case 30:
+ case 60:
+ if (!(timecode.drop)) {
+ timecode.frames = 0;
+ } else {
+ if ((timecode.minutes % 10) && (timecode.seconds == 0)) {
+ timecode.frames = 2;
+ } else {
+ timecode.frames = 0;
+ }
+ }
+ break;
+ }
+
+ if (Timecode_IS_ZERO (timecode)) {
+ timecode.negative = false;
+ }
+}
+
+
+/** Go to next whole minute (seconds == 0, frames == 0 or frames == 2) */
+Wrap
+increment_minutes (Time& timecode, uint32_t subframes_per_frame)
+{
+ Wrap wrap = NONE;
+
+ // Clear subframes
+ frames_floot (timecode);
+
+ if (timecode.negative) {
+ // Wrap if on minute boundary
+ wrap = increment_seconds (timecode, subframes_per_frame);
+ // Go to lowest possible value in this minute
+ minutes_floor (timecode);
+ } else {
+ // Go to highest possible second
+ timecode.seconds = 59;
+ // Wrap minute by incrementing second
+ wrap = increment_seconds (timecode, subframes_per_frame);
+ }
+
+ return wrap;
+}
+
+
+/** Go to lowest absolute value in this minute */
+void
+minutes_floor (Time& timecode)
+{
+ // Go to lowest possible second
+ timecode.seconds = 0;
+ // Go to lowest possible frame
+ seconds_floor (timecode);
+
+ if (Timecode_IS_ZERO (timecode)) {
+ timecode.negative = false;
+ }
+}
+
+
+/** Go to next whole hour (minute = 0, second = 0, frame = 0) */
+Wrap
+increment_hours (Time& timecode, uint32_t subframes_per_frame)
+{
+ Wrap wrap = NONE;
+
+ // Clear subframes
+ frames_floot (timecode);
+
+ if (timecode.negative) {
+ // Wrap if on hour boundary
+ wrap = increment_minutes (timecode, subframes_per_frame);
+ // Go to lowest possible value in this hour
+ hours_floor(timecode);
+ } else {
+ timecode.minutes = 59;
+ wrap = increment_minutes (timecode, subframes_per_frame);
+ }
+
+ return wrap;
+}
+
+
+/** Go to lowest absolute value in this hour */
+void
+hours_floor(Time& timecode)
+{
+ timecode.minutes = 0;
+ timecode.seconds = 0;
+ timecode.frames = 0;
+ timecode.subframes = 0;
+
+ if (Timecode_IS_ZERO (timecode)) {
+ timecode.negative = false;
+ }
+}
+
+double
+timecode_to_frames_per_second(TimecodeFormat t)
+{
+ switch (t) {
+ case timecode_23976:
+ return (24000.0/1001.0); //23.976;
+
+ break;
+ case timecode_24:
+ return 24;
+
+ break;
+ case timecode_24976:
+ return (25000.0/1001.0); //24.976;
+
+ break;
+ case timecode_25:
+ return 25;
+
+ break;
+ case timecode_2997:
+ return (30000.0/1001.0); //29.97;
+
+ break;
+ case timecode_2997drop:
+ return (30000.0/1001.0); //29.97;
+
+ break;
+ case timecode_2997000:
+ return 29.97;
+
+ break;
+ case timecode_2997000drop:
+ return 29.97;
+
+ break;
+ case timecode_30:
+ return 30;
+
+ break;
+ case timecode_30drop:
+ return 30;
+
+ break;
+ case timecode_5994:
+ return (60000.0/1001.0); //59.94;
+
+ break;
+ case timecode_60:
+ return 60;
+
+ break;
+ default:
+ //std::cerr << "Editor received unexpected timecode type" << std::endl;
+ break;
+ }
+ return 30.0;
+}
+
+bool
+timecode_has_drop_frames(TimecodeFormat t)
+{
+ switch (t) {
+ case timecode_23976:
+ return false;
+
+ break;
+ case timecode_24:
+ return false;
+
+ break;
+ case timecode_24976:
+ return false;
+
+ break;
+ case timecode_25:
+ return false;
+
+ break;
+ case timecode_2997:
+ return false;
+
+ break;
+ case timecode_2997drop:
+ return true;
+
+ break;
+ case timecode_2997000:
+ return false;
+
+ break;
+ case timecode_2997000drop:
+ return true;
+
+ break;
+ case timecode_30:
+ return false;
+
+ break;
+ case timecode_30drop:
+ return true;
+
+ break;
+ case timecode_5994:
+ return false;
+
+ break;
+ case timecode_60:
+ return false;
+
+ break;
+ default:
+ //error << "Editor received unexpected timecode type" << endmsg;
+ break;
+ }
+
+ return false;
+}
+
+std::string
+timecode_format_name (TimecodeFormat const t)
+{
+ switch (t) {
+ case timecode_23976:
+ return "23.98";
+
+ break;
+ case timecode_24:
+ return "24";
+
+ break;
+ case timecode_24976:
+ return "24.98";
+
+ break;
+ case timecode_25:
+ return "25";
+
+ break;
+ case timecode_2997000:
+ case timecode_2997:
+ return "29.97";
+
+ break;
+ case timecode_2997000drop:
+ case timecode_2997drop:
+ return "29.97 drop";
+
+ break;
+ case timecode_30:
+ return "30";
+
+ break;
+ case timecode_30drop:
+ return "30 drop";
+
+ break;
+ case timecode_5994:
+ return "59.94";
+
+ break;
+ case timecode_60:
+ return "60";
+
+ break;
+ default:
+ break;
+ }
+
+ return "??";
+}
+
+std::string timecode_format_time (Timecode::Time TC)
+{
+ char buf[32];
+ if (TC.negative) {
+ snprintf (buf, sizeof (buf), "-%02" PRIu32 ":%02" PRIu32 ":%02" PRIu32 "%c%02" PRIu32,
+ TC.hours, TC.minutes, TC.seconds, TC.drop ? ';' : ':', TC.frames);
+ } else {
+ snprintf (buf, sizeof (buf), " %02" PRIu32 ":%02" PRIu32 ":%02" PRIu32 "%c%02" PRIu32,
+ TC.hours, TC.minutes, TC.seconds, TC.drop ? ';' : ':', TC.frames);
+ }
+ return std::string(buf);
+}
+
+std::string timecode_format_sampletime (
+ int64_t sample,
+ double sample_sample_rate,
+ double timecode_frames_per_second, bool timecode_drop_frames)
+{
+ Time t;
+ sample_to_timecode(
+ sample, t, false, false,
+ timecode_frames_per_second, timecode_drop_frames,
+ sample_sample_rate,
+ 80, false, 0);
+ return timecode_format_time(t);
+}
+
+bool parse_timecode_format(std::string tc, Timecode::Time &TC) {
+ char negative[2];
+ char ignored[2];
+ TC.subframes = 0;
+ if (sscanf (tc.c_str(), "%[- ]%" PRId32 ":%" PRId32 ":%" PRId32 "%[:;]%" PRId32,
+ negative, &TC.hours, &TC.minutes, &TC.seconds, ignored, &TC.frames) != 6) {
+ TC.hours = TC.minutes = TC.seconds = TC.frames = 0;
+ TC.negative = false;
+ return false;
+ }
+ if (negative[0]=='-') {
+ TC.negative = true;
+ } else {
+ TC.negative = false;
+ }
+ return true;
+}
+
+void
+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,
+ /* optional offset - can be improved: function pointer to lazily query this*/
+ bool offset_is_negative, int64_t offset_samples
+ )
+{
+ const double samples_per_timecode_frame = (double) sample_sample_rate / (double) timecode.rate;
+
+ if (timecode.drop) {
+ // The drop frame format was created to better approximate the 30000/1001 = 29.97002997002997....
+ // framerate of NTSC color TV. The used frame rate of drop fra,e is 29.97, which drifts by about
+ // 0.108 frame per hour, or about 1.3 frames per 12 hours. This is not perfect, but a lot better
+ // than using 30 non drop, which will drift with about 1.8 frame per minute.
+ // Using 29.97, drop frame real time can be accurate only every 10th minute (10 minutes of 29.97 fps
+ // is exactly 17982 samples). One minute is 1798.2 samples, but we count 30 frames per second
+ // (30 * 60 = 1800). This means that at the first minute boundary (at the end of 0:0:59:29) we
+ // are 1.8 framess too late relative to real time. By dropping 2 frames (jumping to 0:1:0:2) we are
+ // approx. 0.2 frames too early. This adds up with 0.2 too early for each minute until we are 1.8
+ // samples too early at 0:9:0:2 (9 * 0.2 = 1.8). The 10th minute brings us 1.8 frames later again
+ // (at end of 0:9:59:29), which sums up to 0 (we are back to zero at 0:10:0:0 :-).
+ //
+ // In table form:
+ //
+ // Timecode value frames offset subframes offset seconds (rounded) 44100 sample (rounded)
+ // 0:00:00:00 0.0 0 0.000 0 (accurate)
+ // 0:00:59:29 1.8 144 60.027 2647177
+ // 0:01:00:02 -0.2 -16 60.060 2648648
+ // 0:01:59:29 1.6 128 120.020 5292883
+ // 0:02:00:02 -0.4 -32 120.053 5294354
+ // 0:02:59:29 1.4 112 180.013 7938588
+ // 0:03:00:02 -0.6 -48 180.047 7940060
+ // 0:03:59:29 1.2 96 240.007 10584294
+ // 0:04:00:02 -0.8 -64 240.040 10585766
+ // 0:04:59:29 1.0 80 300.000 13230000
+ // 0:05:00:02 -1.0 -80 300.033 13231471
+ // 0:05:59:29 0.8 64 359.993 15875706
+ // 0:06:00:02 -1.2 -96 360.027 15877177
+ // 0:06:59:29 0.6 48 419.987 18521411
+ // 0:07:00:02 -1.4 -112 420.020 18522883
+ // 0:07:59:29 0.4 32 478.980 21167117
+ // 0:08:00:02 -1.6 -128 480.013 21168589
+ // 0:08:59:29 0.2 16 539.973 23812823
+ // 0:09:00:02 -1.8 -144 540.007 23814294
+ // 0:09:59:29 0.0+ 0+ 599.967 26458529
+ // 0:10:00:00 0.0 0 600.000 26460000 (accurate)
+ //
+ // Per Sigmond <per@sigmond.no>
+ //
+ // This schma would compensate exactly for a frame-rate of 30 * 0.999. but the
+ // actual rate is 30000/1001 - which results in an offset of -3.6ms per hour or
+ // about -86ms over a 24-hour period. (SMPTE 12M-1999)
+ //
+ // Robin Gareus <robin@gareus.org>
+
+ const int64_t fps_i = ceil(timecode.rate);
+ int64_t totalMinutes = 60 * timecode.hours + timecode.minutes;
+ int64_t frameNumber = fps_i * 3600 * timecode.hours
+ + fps_i * 60 * timecode.minutes
+ + fps_i * timecode.seconds + timecode.frames
+ - 2 * (totalMinutes - totalMinutes / 10);
+ sample = frameNumber * sample_sample_rate / (double) timecode.rate;
+ } else {
+ /*
+ Non drop is easy.. just note the use of
+ rint(timecode.rate) * samples_per_timecode_frame
+ (frames per Timecode second), which is larger than
+ sample_rate() in the non-integer Timecode rate case.
+ */
+
+ sample = (int64_t) rint(
+ (
+ ((timecode.hours * 60 * 60) + (timecode.minutes * 60) + timecode.seconds)
+ *
+ (rint(timecode.rate) * samples_per_timecode_frame)
+ )
+ + (timecode.frames * samples_per_timecode_frame)
+ );
+ }
+
+ if (use_subframes) {
+ sample += (int64_t) rint(((double)timecode.subframes * samples_per_timecode_frame) / (double)subframes_per_frame);
+ }
+
+ if (use_offset) {
+ if (offset_is_negative) {
+ if (sample >= offset_samples) {
+ sample -= offset_samples;
+ } else {
+ /* Prevent song-time from becoming negative */
+ sample = 0;
+ }
+ } else {
+ if (timecode.negative) {
+ if (sample <= offset_samples) {
+ sample = offset_samples - sample;
+ } else {
+ sample = 0;
+ }
+ } else {
+ sample += offset_samples;
+ }
+ }
+ }
+}
+
+
+void
+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
+ )
+{
+ int64_t offset_sample;
+
+ if (!use_offset) {
+ timecode.negative = (sample < 0);
+ offset_sample = ::llabs(sample);
+ } else {
+ if (offset_is_negative) {
+ offset_sample = sample + offset_samples;
+ timecode.negative = false;
+ } else {
+ if (sample < offset_samples) {
+ offset_sample = (offset_samples - sample);
+ timecode.negative = true;
+ } else {
+ offset_sample = sample - offset_samples;
+ timecode.negative = false;
+ }
+ }
+ }
+
+ if (timecode_drop_frames) {
+ int64_t frameNumber = floor( (double)offset_sample * timecode_frames_per_second / sample_sample_rate);
+
+ /* there are 17982 samples in 10 min @ 29.97df */
+ const int64_t D = frameNumber / 17982;
+ const int64_t M = frameNumber % 17982;
+
+ timecode.subframes = rint(subframes_per_frame
+ * ((double)offset_sample * timecode_frames_per_second / sample_sample_rate - (double)frameNumber));
+
+ if (timecode.subframes == subframes_per_frame) {
+ timecode.subframes = 0;
+ frameNumber++;
+ }
+
+ frameNumber += 18*D + 2*((M - 2) / 1798);
+
+ timecode.frames = frameNumber % 30;
+ timecode.seconds = (frameNumber / 30) % 60;
+ timecode.minutes = ((frameNumber / 30) / 60) % 60;
+ timecode.hours = (((frameNumber / 30) / 60) / 60);
+
+ } else {
+ double timecode_frames_left_exact;
+ double timecode_frames_fraction;
+ int64_t timecode_frames_left;
+ const double samples_per_timecode_frame = sample_sample_rate / timecode_frames_per_second;
+ const int64_t frames_per_hour = (int64_t)(3600. * rint(timecode_frames_per_second) * samples_per_timecode_frame);
+
+ timecode.hours = offset_sample / frames_per_hour;
+
+ // Extract whole hours. Do this to prevent rounding errors with
+ // high sample numbers in the calculations that follow.
+ timecode_frames_left_exact = (double)(offset_sample % frames_per_hour) / samples_per_timecode_frame;
+ timecode_frames_fraction = timecode_frames_left_exact - floor( timecode_frames_left_exact );
+
+ timecode.subframes = (int32_t) rint(timecode_frames_fraction * subframes_per_frame);
+ timecode_frames_left = (int64_t) floor (timecode_frames_left_exact);
+
+ if (use_subframes && timecode.subframes == subframes_per_frame) {
+ timecode_frames_left++;
+ timecode.subframes = 0;
+ }
+
+ timecode.minutes = timecode_frames_left / ((int32_t) lrint (timecode_frames_per_second) * 60);
+ timecode_frames_left = timecode_frames_left % ((int32_t) lrint (timecode_frames_per_second) * 60);
+ timecode.seconds = timecode_frames_left / (int32_t) lrint(timecode_frames_per_second);
+ timecode.frames = timecode_frames_left % (int32_t) lrint(timecode_frames_per_second);
+ }
+
+ if (!use_subframes) {
+ timecode.subframes = 0;
+ }
+ /* set frame rate and drop sample */
+ timecode.rate = timecode_frames_per_second;
+ timecode.drop = timecode_drop_frames;
+}
+
+} // namespace Timecode
+
+std::ostream&
+operator<<(std::ostream& ostr, const Timecode::Time& t)
+{
+ return t.print (ostr);
+}
diff --git a/libs/temporal/types.h b/libs/temporal/types.h
new file mode 100644
index 0000000000..1d19245ec8
--- /dev/null
+++ b/libs/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/wscript b/libs/temporal/wscript
new file mode 100644
index 0000000000..fadeb0aebd
--- /dev/null
+++ b/libs/temporal/wscript
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+from waflib.extras import autowaf as autowaf
+from waflib import Options
+import os
+
+# Mandatory variables
+top = '.'
+out = 'build'
+
+def options(opt):
+ autowaf.set_options(opt)
+
+def configure(conf):
+ conf.load('compiler_cxx')
+ autowaf.configure(conf)
+
+def build(bld):
+ bld.shlib (
+ source = [ 'src/time.cc', 'src/bbt_time.cc' ],
+ name = 'libtimecode',
+ target = 'timecode',
+ includes = ['.'],
+ export_includes = ['.'],
+ defines = [ 'LIBTIMECODE_DLL_EXPORTS' ],
+ install_path = bld.env['LIBDIR']
+ )
+
+def shutdown():
+ autowaf.shutdown()