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 | |
parent | 8890494ba31b007b1b138f5e7ebdb35f192a0cfd (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.vcproj | 300 | ||||
-rw-r--r-- | libs/temporal/bbt_time.cc | 50 | ||||
-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 | ||||
-rw-r--r-- | libs/temporal/time.cc | 853 | ||||
-rw-r--r-- | libs/temporal/types.h | 46 | ||||
-rw-r--r-- | libs/temporal/wscript | 29 |
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;"$(GenericIncludeFolder)\ardourext";..\..\surfaces\control_protocol;..\..\evoral;..\..\libltc;..\..\rubberband;"..\..\vamp-sdk";"..\..\midi++2";..\..\taglib;..\..\taglib\taglib;..\..\taglib\taglib\toolkit;..\..\audiographer;"$(GenericLibraryFolder)\glib-2.0\include";"$(GenericIncludeFolder)\glibmm";"$(GenericIncludeFolder)\libsndfile";"$(GenericIncludeFolder)\gtk-2.0";"$(GenericIncludeFolder)\cairo";"$(GenericIncludeFolder)\pango-1.0";"$(GenericIncludeFolder)\gtk-2.0\gdk";"$(GenericIncludeFolder)\atk-2.0";"$(GenericIncludeFolder)\lrdf";"$(GenericIncludeFolder)\raptor";"$(GenericIncludeFolder)\lilv-0";"$(GenericIncludeFolder)\suil-0";"$(GenericIncludeFolder)\serd-0";"$(GenericIncludeFolder)\sord-0";"$(GenericIncludeFolder)\lv2";"$(GenericIncludeFolder)\sratom-0"" + 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="Debug";ARCH_X86;USE_XMMINTRIN;BUILD_SSE_OPTIMIZATIONS;ENABLE_NLS;PACKAGE="\"ardour3_timecode\"";PROGRAM_NAME="\"Mixbus3\"";_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=\"Mod4><Super\";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=\"1.2\";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 "$(OutDir)\$(TargetName).dll" "$(Debug32TargetFolder)\$(TargetName).dll"
copy /Y "$(OutDir)\$(TargetName).dll" "$(Debug32TestSuiteFolder)\$(TargetName).dll"
copy /Y "$(OutDir)\$(TargetName).lib" "$(GenericWin32LibraryFolder)\$(TargetName).lib"
" + /> + </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;"$(GenericIncludeFolder)\ardourext";..\..\surfaces\control_protocol;..\..\evoral;..\..\libltc;..\..\rubberband;"..\..\vamp-sdk";"..\..\midi++2";..\..\taglib;..\..\taglib\taglib;..\..\taglib\taglib\toolkit;..\..\audiographer;"$(GenericLibraryFolder)\glib-2.0\include";"$(GenericIncludeFolder)\glibmm";"$(GenericIncludeFolder)\libsndfile";"$(GenericIncludeFolder)\gtk-2.0";"$(GenericIncludeFolder)\cairo";"$(GenericIncludeFolder)\pango-1.0";"$(GenericIncludeFolder)\gtk-2.0\gdk";"$(GenericIncludeFolder)\atk-2.0";"$(GenericIncludeFolder)\lrdf";"$(GenericIncludeFolder)\raptor";"$(GenericIncludeFolder)\lilv-0";"$(GenericIncludeFolder)\suil-0";"$(GenericIncludeFolder)\serd-0";"$(GenericIncludeFolder)\sord-0";"$(GenericIncludeFolder)\lv2";"$(GenericIncludeFolder)\sratom-0"" + 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="\"ardour3_timecode\"";PROGRAM_NAME="\"Mixbus3\"";_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=\"Mod4><Super\";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=\"1.2\";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 "$(OutDir)\$(TargetName).dll" "$(Release32TargetFolder)\$(TargetName).dll"
copy /Y "$(OutDir)\$(TargetName).dll" "$(Release32TestSuiteFolder)\$(TargetName).dll"
copy /Y "$(OutDir)\$(TargetName).lib" "$(GenericWin32LibraryFolder)\$(TargetName).lib"
" + /> + </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;"$(GenericIncludeFolder)\ardourext";..\..\surfaces\control_protocol;..\..\evoral;..\..\libltc;..\..\rubberband;"..\..\vamp-sdk";"..\..\midi++2";..\..\taglib;..\..\taglib\taglib;..\..\taglib\taglib\toolkit;..\..\audiographer;"$(GenericLibraryFolder)\glib-2.0\include";"$(GenericIncludeFolder)\glibmm";"$(GenericIncludeFolder)\libsndfile";"$(GenericIncludeFolder)\gtk-2.0";"$(GenericIncludeFolder)\cairo";"$(GenericIncludeFolder)\pango-1.0";"$(GenericIncludeFolder)\gtk-2.0\gdk";"$(GenericIncludeFolder)\atk-2.0";"$(GenericIncludeFolder)\lrdf";"$(GenericIncludeFolder)\raptor";"$(GenericIncludeFolder)\lilv-0";"$(GenericIncludeFolder)\suil-0";"$(GenericIncludeFolder)\serd-0";"$(GenericIncludeFolder)\sord-0";"$(GenericIncludeFolder)\lv2";"$(GenericIncludeFolder)\sratom-0"" + 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="\"ardour3_timecode\"";PROGRAM_NAME="\"Mixbus3\"";_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=\"Mod4><Super\";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=\"1.2\";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 "$(OutDir)\$(TargetName).dll" "$(Release32TestSuiteFolder)\$(TargetName).dll"
copy /Y "$(OutDir)\$(TargetName).lib" "$(GenericWin32LibraryFolder)\$(TargetName).lib"
" + /> + </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() |