Merge branch 'master' into saveas

Conflicts:
	gtk2_ardour/ardour.menus.in
	libs/ardour/session_state.cc
This commit is contained in:
Paul Davis 2015-04-20 15:10:41 -04:00
commit ced4378d09
602 changed files with 94298 additions and 65112 deletions

View file

@ -305,8 +305,8 @@ bool CAAudioUnit::CanDo ( int inChannelsIn,
// is expected to deal with same channel valance in and out
if (result)
{
if (Comp().Desc().IsEffect() && (inChannelsIn == inChannelsOut)
|| Comp().Desc().IsOffline() && (inChannelsIn == inChannelsOut))
if ((Comp().Desc().IsEffect() && (inChannelsIn == inChannelsOut))
|| (Comp().Desc().IsOffline() && (inChannelsIn == inChannelsOut)))
{
return true;
}
@ -348,6 +348,41 @@ int CAAudioUnit::GetChannelInfo (AUChannelInfo** chaninfo, UInt32& cnt)
{
return 1;
}
else if (Comp().Desc().IsGenerator() || Comp().Desc().IsMusicDevice()) {
// directly query Bus Formats
// Note that that these may refer to different subBusses
// (eg. Kick, Snare,.. on a Drummachine)
// eventually the Bus-Name for each configuration should be exposed
// for the User to select..
UInt32 elCountIn, elCountOut;
if (GetElementCount (kAudioUnitScope_Input, elCountIn)) return -1;
if (GetElementCount (kAudioUnitScope_Output, elCountOut)) return -1;
cnt = std::max(elCountIn, elCountOut);
*chaninfo = (AUChannelInfo*) malloc (sizeof (AUChannelInfo) * cnt);
for (unsigned int i = 0; i < elCountIn; ++i) {
UInt32 numChans;
if (NumberChannels (kAudioUnitScope_Input, i, numChans)) return -1;
(*chaninfo)[i].inChannels = numChans;
}
for (unsigned int i = elCountIn; i < cnt; ++i) {
(*chaninfo)[i].inChannels = 0;
}
for (unsigned int i = 0; i < elCountOut; ++i) {
UInt32 numChans;
if (NumberChannels (kAudioUnitScope_Output, i, numChans)) return -1;
(*chaninfo)[i].outChannels = numChans;
}
for (unsigned int i = elCountOut; i < cnt; ++i) {
(*chaninfo)[i].outChannels = 0;
}
return 0;
}
else
{
// the au should either really tell us about this

View file

@ -42,7 +42,7 @@
AdditionalOptions="/FI$(TargetSxsFolder)\targetsxs.h"
Optimization="0"
AdditionalIncludeDirectories="..;..\..\ardour;..\..\pbd;..\..\fst;&quot;$(GenericIncludeFolder)\ardourext&quot;;..\..\surfaces\control_protocol;..\..\evoral;..\..\libltc;..\..\timecode;&quot;..\..\midi++2&quot;;..\..\audiographer;&quot;$(GenericIncludeFolder)\taglib&quot;;&quot;$(GenericIncludeFolder)\taglib\toolkit&quot;;&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;DEBUGGABLE_BACKENDS;DEBUGGABLE_SCANNER_APP;BUILDING_LIBARDOUR;LIBARDOUR_DLL_EXPORTS;RUBBERBAND_IS_IN_WIN_STATIC_LIB;USE_CAIRO_IMAGE_SURFACE;NOMINMAX;NO_POSIX_MEMALIGN;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;ENABLE_NLS;PACKAGE=&quot;\&quot;ardour3\&quot;&quot;;PROGRAM_NAME=&quot;\&quot;Mixbus3\&quot;&quot;;PROGRAM_VERSION=&quot;\&quot;\&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=3001"
PreprocessorDefinitions="PLATFORM_WINDOWS;COMPILER_MSVC;DEBUGGABLE_BACKENDS;DEBUGGABLE_SCANNER_APP;BUILDING_LIBARDOUR;LIBARDOUR_DLL_EXPORTS;LIBARDOUR=\&quot;mixbus3\&quot;;RUBBERBAND_IS_IN_WIN_STATIC_LIB;USE_CAIRO_IMAGE_SURFACE;NOMINMAX;NO_POSIX_MEMALIGN;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;ENABLE_NLS;PACKAGE=&quot;\&quot;ardour3\&quot;&quot;;PROGRAM_NAME=&quot;\&quot;Mixbus\&quot;&quot;;PROGRAM_VERSION=&quot;\&quot;3\&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=3001"
MinimalRebuild="true"
RuntimeLibrary="3"
WarningLevel="3"
@ -60,7 +60,7 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="libfftw3-3.lib libfftw3f-3.lib libfftw3l-3.lib libeay32.lib iconvD.lib zlib1D.lib boost-regex32D.lib $(DllPrefix)atkmm32$(AtkmmDllSuffix)D.lib $(DllPrefix)gtkmm32$(GtkmmDllSuffix)D.lib $(DllPrefix)gdkmm32$(GtkmmDllSuffix)D.lib $(DllPrefix)glibmm32$(GlibmmDllSuffix)D.lib $(DllPrefix)giomm32$(GlibmmDllSuffix)D.lib $(DllPrefix)cairomm32$(CairommDllSuffix)D.lib $(DllPrefix)pangomm32$(PangommDllSuffix)D.lib pthreadVCE2.lib $(DllPrefix)pango32$(PangoDllSuffix)D.lib $(DllPrefix)pangoft232$(PangoDllSuffix)D.lib $(DllPrefix)pangowin32$(PangoDllSuffix)D.lib $(DllPrefix)pangocairo32$(PangoDllSuffix)D.lib $(DllPrefix)cairo32$(CairoDllSuffix)D.lib $(DllPrefix)atk32$(AtkDllSuffix)D.lib $(DllPrefix)gthread32$(GlibDllSuffix)D.lib $(DllPrefix)gobject32$(GlibDllSuffix)D.lib $(DllPrefix)gmodule32$(GlibDllSuffix)D.lib $(DllPrefix)glib32$(GlibDllSuffix)D.lib $(DllPrefix)gio32$(GlibDllSuffix)D.lib $(DllPrefix)gtk32$(GtkDllSuffix)D.lib $(DllPrefix)gdk32$(GtkDllSuffix)D.lib $(DllPrefix)gdk-pixbuf32$(GdkPixbufDllSuffix)D.lib $(DllPrefix)sigc++32-2.0D.lib $(DllPrefix)curlD.lib $(DllPrefix)fontconfigD.lib $(DllPrefix)timecode32D.lib $(DllPrefix)taglib32D.lib freetype32-2D.lib raptor2D.lib lrdfD.lib libloD.lib rubberbandD.lib $(DllPrefix)ltcD.lib $(DllPrefix)audiographer32D.lib $(DllPrefix)pbd32D.lib $(DllPrefix)midi++32D.lib $(DllPrefix)evoral32D.lib $(DllPrefix)sndfile-1D.lib $(DllPrefix)samplerate-0D.lib vampsdkD.lib vamphostsdkD.lib $(DllPrefix)lilv32-0D.lib suil-0D.lib $(DllPrefix)serd32-0D.lib $(DllPrefix)sord32-0D.lib $(DllPrefix)sratom32-0D.lib libart_lgpl_2D.lib libjackD.lib libxml2D.lib intlD.lib shell32.lib psapi.lib ws2_32.lib winmm.lib"
AdditionalDependencies="libfftw3-3.lib libfftw3f-3.lib libfftw3l-3.lib libeay32.lib iconvD.lib zlib1D.lib boost-regex32D.lib $(DllPrefix)atkmm32$(AtkmmDllSuffix)D.lib $(DllPrefix)gtkmm32$(GtkmmDllSuffix)D.lib $(DllPrefix)gdkmm32$(GtkmmDllSuffix)D.lib $(DllPrefix)glibmm32$(GlibmmDllSuffix)D.lib $(DllPrefix)giomm32$(GlibmmDllSuffix)D.lib $(DllPrefix)cairomm32$(CairommDllSuffix)D.lib $(DllPrefix)pangomm32$(PangommDllSuffix)D.lib pthreadVCE2.lib $(DllPrefix)pango32$(PangoDllSuffix)D.lib $(DllPrefix)pangoft232$(PangoDllSuffix)D.lib $(DllPrefix)pangowin32$(PangoDllSuffix)D.lib $(DllPrefix)pangocairo32$(PangoDllSuffix)D.lib $(DllPrefix)cairo32$(CairoDllSuffix)D.lib $(DllPrefix)atk32$(AtkDllSuffix)D.lib $(DllPrefix)gthread32$(GlibDllSuffix)D.lib $(DllPrefix)gobject32$(GlibDllSuffix)D.lib $(DllPrefix)gmodule32$(GlibDllSuffix)D.lib $(DllPrefix)glib32$(GlibDllSuffix)D.lib $(DllPrefix)gio32$(GlibDllSuffix)D.lib $(DllPrefix)gtk32$(GtkDllSuffix)D.lib $(DllPrefix)gdk32$(GtkDllSuffix)D.lib $(DllPrefix)gdk-pixbuf32$(GdkPixbufDllSuffix)D.lib $(DllPrefix)sigc++32-2.0D.lib $(DllPrefix)curlD.lib $(DllPrefix)fontconfigD.lib $(DllPrefix)timecode32D.lib $(DllPrefix)taglib32D.lib freetype32-2D.lib raptor2D.lib lrdfD.lib libloD.lib rubberbandD.lib $(DllPrefix)ltcD.lib $(DllPrefix)audiographer32D.lib $(DllPrefix)pbd32D.lib $(DllPrefix)midi++32D.lib $(DllPrefix)evoral32D.lib $(DllPrefix)sndfile-1D.lib $(DllPrefix)samplerate-0D.lib vampsdkD.lib vamphostsdkD.lib $(DllPrefix)lilv32-0D.lib $(DllPrefix)suil32-0D.lib $(DllPrefix)serd32-0D.lib $(DllPrefix)sord32-0D.lib $(DllPrefix)sratom32-0D.lib libart_lgpl_2D.lib libjackD.lib libxml2D.lib intlD.lib shell32.lib psapi.lib ws2_32.lib winmm.lib"
OutputFile="$(OutDir)\$(DllPrefix)$(ProjectName)32D.dll"
AdditionalLibraryDirectories="F:\pthread-win32\Pre-built.2\lib"
IgnoreDefaultLibraryNames="libboost_regex-vc80-mt-gd-1_40.lib;msvcrt.lib;dsound.lib"
@ -124,7 +124,7 @@
Optimization="2"
InlineFunctionExpansion="1"
AdditionalIncludeDirectories="..;..\..\ardour;..\..\pbd;..\..\fst;&quot;$(GenericIncludeFolder)\ardourext&quot;;..\..\surfaces\control_protocol;..\..\evoral;..\..\libltc;..\..\timecode;&quot;..\..\midi++2&quot;;..\..\audiographer;&quot;$(GenericIncludeFolder)\taglib&quot;;&quot;$(GenericIncludeFolder)\taglib\toolkit&quot;;&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;_SECURE_SCL=0;BUILDING_LIBARDOUR;LIBARDOUR_DLL_EXPORTS;RUBBERBAND_IS_IN_WIN_STATIC_LIB;USE_CAIRO_IMAGE_SURFACE;NOMINMAX;NO_POSIX_MEMALIGN;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;ENABLE_NLS;PACKAGE=&quot;\&quot;ardour3\&quot;&quot;;PROGRAM_NAME=&quot;\&quot;Mixbus3\&quot;&quot;;PROGRAM_VERSION=&quot;\&quot;\&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=3001"
PreprocessorDefinitions="PLATFORM_WINDOWS;COMPILER_MSVC;_SECURE_SCL=0;BUILDING_LIBARDOUR;LIBARDOUR_DLL_EXPORTS;LIBARDOUR=\&quot;mixbus3\&quot;;RUBBERBAND_IS_IN_WIN_STATIC_LIB;USE_CAIRO_IMAGE_SURFACE;NOMINMAX;NO_POSIX_MEMALIGN;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;ENABLE_NLS;PACKAGE=&quot;\&quot;ardour3\&quot;&quot;;PROGRAM_NAME=&quot;\&quot;Mixbus\&quot;&quot;;PROGRAM_VERSION=&quot;\&quot;3\&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=3001"
StringPooling="false"
RuntimeLibrary="2"
EnableEnhancedInstructionSet="1"
@ -142,7 +142,7 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="libfftw3-3.lib libfftw3f-3.lib libfftw3l-3.lib libeay32.lib iconv.lib zlib1.lib boost-regex32.lib $(DllPrefix)atkmm32$(AtkmmDllSuffix).lib $(DllPrefix)gtkmm32$(GtkmmDllSuffix).lib $(DllPrefix)gdkmm32$(GtkmmDllSuffix).lib $(DllPrefix)glibmm32$(GlibmmDllSuffix).lib $(DllPrefix)giomm32$(GlibmmDllSuffix).lib $(DllPrefix)cairomm32$(CairommDllSuffix).lib $(DllPrefix)pangomm32$(PangommDllSuffix).lib pthreadVCE2.lib $(DllPrefix)pango32$(PangoDllSuffix).lib $(DllPrefix)pangoft232$(PangoDllSuffix).lib $(DllPrefix)pangowin32$(PangoDllSuffix).lib $(DllPrefix)pangocairo32$(PangoDllSuffix).lib $(DllPrefix)cairo32$(CairoDllSuffix).lib $(DllPrefix)atk32$(AtkDllSuffix).lib $(DllPrefix)gthread32$(GlibDllSuffix).lib $(DllPrefix)gobject32$(GlibDllSuffix).lib $(DllPrefix)gmodule32$(GlibDllSuffix).lib $(DllPrefix)glib32$(GlibDllSuffix).lib $(DllPrefix)gio32$(GlibDllSuffix).lib $(DllPrefix)gtk32$(GtkDllSuffix).lib $(DllPrefix)gdk32$(GtkDllSuffix).lib $(DllPrefix)gdk-pixbuf32$(GdkPixbufDllSuffix).lib $(DllPrefix)sigc++32-2.0.lib $(DllPrefix)curl.lib $(DllPrefix)fontconfig.lib $(DllPrefix)timecode32.lib $(DllPrefix)taglib32.lib freetype32-2.lib raptor2.lib lrdf.lib liblo.lib rubberband.lib $(DllPrefix)ltc.lib $(DllPrefix)audiographer32.lib $(DllPrefix)pbd32.lib $(DllPrefix)midi++32.lib $(DllPrefix)evoral32.lib $(DllPrefix)sndfile-1.lib $(DllPrefix)samplerate-0.lib vampsdk.lib vamphostsdk.lib $(DllPrefix)lilv32-0.lib suil-0.lib $(DllPrefix)serd32-0.lib $(DllPrefix)sord32-0.lib $(DllPrefix)sratom32-0.lib libart_lgpl_2.lib libjack.lib libxml2.lib intl.lib shell32.lib psapi.lib ws2_32.lib winmm.lib"
AdditionalDependencies="libfftw3-3.lib libfftw3f-3.lib libfftw3l-3.lib libeay32.lib iconv.lib zlib1.lib boost-regex32.lib $(DllPrefix)atkmm32$(AtkmmDllSuffix).lib $(DllPrefix)gtkmm32$(GtkmmDllSuffix).lib $(DllPrefix)gdkmm32$(GtkmmDllSuffix).lib $(DllPrefix)glibmm32$(GlibmmDllSuffix).lib $(DllPrefix)giomm32$(GlibmmDllSuffix).lib $(DllPrefix)cairomm32$(CairommDllSuffix).lib $(DllPrefix)pangomm32$(PangommDllSuffix).lib pthreadVCE2.lib $(DllPrefix)pango32$(PangoDllSuffix).lib $(DllPrefix)pangoft232$(PangoDllSuffix).lib $(DllPrefix)pangowin32$(PangoDllSuffix).lib $(DllPrefix)pangocairo32$(PangoDllSuffix).lib $(DllPrefix)cairo32$(CairoDllSuffix).lib $(DllPrefix)atk32$(AtkDllSuffix).lib $(DllPrefix)gthread32$(GlibDllSuffix).lib $(DllPrefix)gobject32$(GlibDllSuffix).lib $(DllPrefix)gmodule32$(GlibDllSuffix).lib $(DllPrefix)glib32$(GlibDllSuffix).lib $(DllPrefix)gio32$(GlibDllSuffix).lib $(DllPrefix)gtk32$(GtkDllSuffix).lib $(DllPrefix)gdk32$(GtkDllSuffix).lib $(DllPrefix)gdk-pixbuf32$(GdkPixbufDllSuffix).lib $(DllPrefix)sigc++32-2.0.lib $(DllPrefix)curl.lib $(DllPrefix)fontconfig.lib $(DllPrefix)timecode32.lib $(DllPrefix)taglib32.lib freetype32-2.lib raptor2.lib lrdf.lib liblo.lib rubberband.lib $(DllPrefix)ltc.lib $(DllPrefix)audiographer32.lib $(DllPrefix)pbd32.lib $(DllPrefix)midi++32.lib $(DllPrefix)evoral32.lib $(DllPrefix)sndfile-1.lib $(DllPrefix)samplerate-0.lib vampsdk.lib vamphostsdk.lib $(DllPrefix)lilv32-0.lib $(DllPrefix)suil32-0.lib $(DllPrefix)serd32-0.lib $(DllPrefix)sord32-0.lib $(DllPrefix)sratom32-0.lib libart_lgpl_2.lib libjack.lib libxml2.lib intl.lib shell32.lib psapi.lib ws2_32.lib winmm.lib"
OutputFile="$(OutDir)\$(DllPrefix)$(ProjectName)32.dll"
AdditionalLibraryDirectories="F:\pthread-win32\Pre-built.2\lib"
IgnoreDefaultLibraryNames="libboost_regex-vc80-mt-gd-1_40.lib;dsound.lib"
@ -205,7 +205,7 @@
AdditionalOptions="/FI$(TargetSxsFolder)\targetsxs.h"
Optimization="0"
AdditionalIncludeDirectories="..;..\..\ardour;..\..\pbd;..\..\fst;&quot;$(GenericIncludeFolder)\ardourext&quot;;..\..\surfaces\control_protocol;..\..\evoral;..\..\libltc;..\..\timecode;&quot;..\..\midi++2&quot;;..\..\audiographer;&quot;$(GenericIncludeFolder)\taglib&quot;;&quot;$(GenericIncludeFolder)\taglib\toolkit&quot;;&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;DEBUGGABLE_BACKENDS;DEBUGGABLE_SCANNER_APP;COMPILER_MSVC;_SECURE_SCL=0;BUILDING_LIBARDOUR;LIBARDOUR_DLL_EXPORTS;RUBBERBAND_IS_IN_WIN_STATIC_LIB;USE_CAIRO_IMAGE_SURFACE;NOMINMAX;NO_POSIX_MEMALIGN;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;ENABLE_NLS;PACKAGE=&quot;\&quot;ardour3\&quot;&quot;;PROGRAM_NAME=&quot;\&quot;Mixbus3\&quot;&quot;;PROGRAM_VERSION=&quot;\&quot;\&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=3001"
PreprocessorDefinitions="PLATFORM_WINDOWS;DEBUGGABLE_BACKENDS;DEBUGGABLE_SCANNER_APP;COMPILER_MSVC;_SECURE_SCL=0;BUILDING_LIBARDOUR;LIBARDOUR_DLL_EXPORTS;LIBARDOUR=\&quot;mixbus3\&quot;;RUBBERBAND_IS_IN_WIN_STATIC_LIB;USE_CAIRO_IMAGE_SURFACE;NOMINMAX;NO_POSIX_MEMALIGN;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;ENABLE_NLS;PACKAGE=&quot;\&quot;ardour3\&quot;&quot;;PROGRAM_NAME=&quot;\&quot;Mixbus\&quot;&quot;;PROGRAM_VERSION=&quot;\&quot;3\&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=3001"
StringPooling="false"
RuntimeLibrary="2"
EnableEnhancedInstructionSet="1"
@ -224,7 +224,7 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="libfftw3-3.lib libfftw3f-3.lib libfftw3l-3.lib libeay32.lib iconvRDC.lib zlib1RDC.lib boost-regex32RDC.lib $(DllPrefix)atkmm32$(AtkmmDllSuffix)RDC.lib $(DllPrefix)gtkmm32$(GtkmmDllSuffix)RDC.lib $(DllPrefix)gdkmm32$(GtkmmDllSuffix)RDC.lib $(DllPrefix)glibmm32$(GlibmmDllSuffix)RDC.lib $(DllPrefix)giomm32$(GlibmmDllSuffix)RDC.lib $(DllPrefix)cairomm32$(CairommDllSuffix)RDC.lib $(DllPrefix)pangomm32$(PangommDllSuffix)RDC.lib pthreadVCE2.lib $(DllPrefix)pango32$(PangoDllSuffix)RDC.lib $(DllPrefix)pangoft232$(PangoDllSuffix)RDC.lib $(DllPrefix)pangowin32$(PangoDllSuffix)RDC.lib $(DllPrefix)pangocairo32$(PangoDllSuffix)RDC.lib $(DllPrefix)cairo32$(CairoDllSuffix)RDC.lib $(DllPrefix)atk32$(AtkDllSuffix)RDC.lib $(DllPrefix)gthread32$(GlibDllSuffix)RDC.lib $(DllPrefix)gobject32$(GlibDllSuffix)RDC.lib $(DllPrefix)gmodule32$(GlibDllSuffix)RDC.lib $(DllPrefix)glib32$(GlibDllSuffix)RDC.lib $(DllPrefix)gio32$(GlibDllSuffix)RDC.lib $(DllPrefix)gtk32$(GtkDllSuffix)RDC.lib $(DllPrefix)gdk32$(GtkDllSuffix)RDC.lib $(DllPrefix)gdk-pixbuf32$(GdkPixbufDllSuffix)RDC.lib $(DllPrefix)sigc++32-2.0RDC.lib $(DllPrefix)curlRDC.lib $(DllPrefix)fontconfigRDC.lib $(DllPrefix)timecode32RDC.lib $(DllPrefix)taglib32RDC.lib freetype32-2RDC.lib raptor2.lib lrdf.lib libloRDC.lib rubberbandRDC.lib $(DllPrefix)ltcRDC.lib $(DllPrefix)audiographer32RDC.lib $(DllPrefix)pbd32RDC.lib $(DllPrefix)midi++32RDC.lib $(DllPrefix)evoral32RDC.lib $(DllPrefix)sndfile-1.lib $(DllPrefix)samplerate-0.lib vampsdkRDC.lib vamphostsdkRDC.lib $(DllPrefix)lilv32-0RDC.lib suil-0RDC.lib $(DllPrefix)serd32-0RDC.lib $(DllPrefix)sord32-0RDC.lib $(DllPrefix)sratom32-0RDC.lib libart_lgpl_2.lib libjack.lib libxml2.lib intlRDC.lib shell32.lib psapi.lib ws2_32.lib winmm.lib"
AdditionalDependencies="libfftw3-3.lib libfftw3f-3.lib libfftw3l-3.lib libeay32.lib iconvRDC.lib zlib1RDC.lib boost-regex32RDC.lib $(DllPrefix)atkmm32$(AtkmmDllSuffix)RDC.lib $(DllPrefix)gtkmm32$(GtkmmDllSuffix)RDC.lib $(DllPrefix)gdkmm32$(GtkmmDllSuffix)RDC.lib $(DllPrefix)glibmm32$(GlibmmDllSuffix)RDC.lib $(DllPrefix)giomm32$(GlibmmDllSuffix)RDC.lib $(DllPrefix)cairomm32$(CairommDllSuffix)RDC.lib $(DllPrefix)pangomm32$(PangommDllSuffix)RDC.lib pthreadVCE2.lib $(DllPrefix)pango32$(PangoDllSuffix)RDC.lib $(DllPrefix)pangoft232$(PangoDllSuffix)RDC.lib $(DllPrefix)pangowin32$(PangoDllSuffix)RDC.lib $(DllPrefix)pangocairo32$(PangoDllSuffix)RDC.lib $(DllPrefix)cairo32$(CairoDllSuffix)RDC.lib $(DllPrefix)atk32$(AtkDllSuffix)RDC.lib $(DllPrefix)gthread32$(GlibDllSuffix)RDC.lib $(DllPrefix)gobject32$(GlibDllSuffix)RDC.lib $(DllPrefix)gmodule32$(GlibDllSuffix)RDC.lib $(DllPrefix)glib32$(GlibDllSuffix)RDC.lib $(DllPrefix)gio32$(GlibDllSuffix)RDC.lib $(DllPrefix)gtk32$(GtkDllSuffix)RDC.lib $(DllPrefix)gdk32$(GtkDllSuffix)RDC.lib $(DllPrefix)gdk-pixbuf32$(GdkPixbufDllSuffix)RDC.lib $(DllPrefix)sigc++32-2.0RDC.lib $(DllPrefix)curlRDC.lib $(DllPrefix)fontconfigRDC.lib $(DllPrefix)timecode32RDC.lib $(DllPrefix)taglib32RDC.lib freetype32-2RDC.lib raptor2.lib lrdf.lib libloRDC.lib rubberbandRDC.lib $(DllPrefix)ltcRDC.lib $(DllPrefix)audiographer32RDC.lib $(DllPrefix)pbd32RDC.lib $(DllPrefix)midi++32RDC.lib $(DllPrefix)evoral32RDC.lib $(DllPrefix)sndfile-1.lib $(DllPrefix)samplerate-0.lib vampsdkRDC.lib vamphostsdkRDC.lib $(DllPrefix)lilv32-0RDC.lib $(DllPrefix)suil32-0RDC.lib $(DllPrefix)serd32-0RDC.lib $(DllPrefix)sord32-0RDC.lib $(DllPrefix)sratom32-0RDC.lib libart_lgpl_2.lib libjack.lib libxml2.lib intlRDC.lib shell32.lib psapi.lib ws2_32.lib winmm.lib"
OutputFile="$(OutDir)\$(DllPrefix)$(ProjectName)32RDC.dll"
AdditionalLibraryDirectories="F:\pthread-win32\Pre-built.2\lib"
IgnoreDefaultLibraryNames="libboost_regex-vc80-mt-gd-1_40.lib;dsound.lib"
@ -643,6 +643,10 @@
RelativePath="..\midi_buffer.cc"
>
</File>
<File
RelativePath="..\midi_channel_filter.cc"
>
</File>
<File
RelativePath="..\midi_clock_slave.cc"
>
@ -735,6 +739,10 @@
RelativePath="..\mute_master.cc"
>
</File>
<File
RelativePath="..\note_fixer.cc"
>
</File>
<File
RelativePath="..\onset_detector.cc"
>
@ -1717,6 +1725,10 @@
RelativePath="..\ardour\midi_buffer.h"
>
</File>
<File
RelativePath="..\ardour\midi_channel_filter.h"
>
</File>
<File
RelativePath="..\ardour\midi_diskstream.h"
>
@ -1817,6 +1829,10 @@
RelativePath="..\ardour\noise.h"
>
</File>
<File
RelativePath="..\ardour\note_fixer.h"
>
</File>
<File
RelativePath="..\ardour\onset_detector.h"
>

View file

@ -41,6 +41,7 @@ Amp::Amp (Session& s)
, _apply_gain(true)
, _apply_gain_automation(false)
, _current_gain(1.0)
, _current_automation_frame (INT64_MAX)
, _gain_automation_buffer(0)
{
Evoral::Parameter p (GainAutomation);
@ -88,14 +89,23 @@ Amp::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end_frame*/,
gain_t* gab = _gain_automation_buffer;
assert (gab);
const float a = 62.78 / _session.nominal_frame_rate(); // 10 Hz LPF
float lpf = _current_gain;
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
Sample* const sp = i->data();
lpf = _current_gain;
for (pframes_t nx = 0; nx < nframes; ++nx) {
sp[nx] *= gab[nx];
sp[nx] *= lpf;
lpf += a * (gab[nx] - lpf);
}
}
_current_gain = gab[nframes-1];
if (lpf < 1e-10) {
_current_gain = 0;
} else {
_current_gain = lpf;
}
} else { /* manual (scalar) gain */
@ -103,8 +113,7 @@ Amp::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end_frame*/,
if (_current_gain != dg) {
Amp::apply_gain (bufs, nframes, _current_gain, dg);
_current_gain = dg;
_current_gain = Amp::apply_gain (bufs, _session.nominal_frame_rate(), nframes, _current_gain, dg);
} else if (_current_gain != 1.0f) {
@ -133,39 +142,34 @@ Amp::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end_frame*/,
_active = _pending_active;
}
void
Amp::apply_gain (BufferSet& bufs, framecnt_t nframes, gain_t initial, gain_t target)
gain_t
Amp::apply_gain (BufferSet& bufs, framecnt_t sample_rate, framecnt_t nframes, gain_t initial, gain_t target)
{
/** Apply a (potentially) declicked gain to the buffers of @a bufs
*/
/** Apply a (potentially) declicked gain to the buffers of @a bufs */
gain_t rv = target;
if (nframes == 0 || bufs.count().n_total() == 0) {
return;
return initial;
}
// if we don't need to declick, defer to apply_simple_gain
if (initial == target) {
apply_simple_gain (bufs, nframes, target);
return;
}
const framecnt_t declick = std::min ((framecnt_t) 128, nframes);
gain_t delta;
double fractional_shift = -1.0/declick;
double fractional_pos;
if (target < initial) {
/* fade out: remove more and more of delta from initial */
delta = -(initial - target);
} else {
/* fade in: add more and more of delta from initial */
delta = target - initial;
return target;
}
/* MIDI Gain */
for (BufferSet::midi_iterator i = bufs.midi_begin(); i != bufs.midi_end(); ++i) {
gain_t delta;
if (target < initial) {
/* fade out: remove more and more of delta from initial */
delta = -(initial - target);
} else {
/* fade in: add more and more of delta from initial */
delta = target - initial;
}
MidiBuffer& mb (*i);
for (MidiBuffer::iterator m = mb.begin(); m != mb.end(); ++m) {
@ -180,131 +184,100 @@ Amp::apply_gain (BufferSet& bufs, framecnt_t nframes, gain_t initial, gain_t tar
/* Audio Gain */
/* Low pass filter coefficient: 1.0 - e^(-2.0 * π * f / 48000) f in Hz.
* for f << SR, approx a ~= 6.2 * f / SR;
*/
const float a = 62.78 / sample_rate; // 10 Hz LPF
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
Sample* const buffer = i->data();
float lpf = initial;
fractional_pos = 1.0;
for (pframes_t nx = 0; nx < declick; ++nx) {
buffer[nx] *= (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
fractional_pos += fractional_shift;
for (pframes_t nx = 0; nx < nframes; ++nx) {
buffer[nx] *= lpf;
lpf += a * (target - lpf);
}
/* now ensure the rest of the buffer has the target value applied, if necessary. */
if (declick != nframes) {
if (target == 0.0) {
memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
} else if (target != 1.0) {
apply_gain_to_buffer (&buffer[declick], nframes - declick, target);
}
if (i == bufs.audio_begin()) {
rv = lpf;
}
}
// 1e-10 ~ 200dB, prevent denormals.
if (rv < 1e-10) return 0;
if (fabsf(rv - 1.0) < 1e-10) return 1.0;
return rv;
}
void
Amp::declick (BufferSet& bufs, framecnt_t nframes, int dir)
{
/* Almost exactly like ::apply_gain() but skips MIDI buffers and has fixed initial+target
values.
*/
if (nframes == 0 || bufs.count().n_total() == 0) {
return;
}
const framecnt_t declick = std::min ((framecnt_t) 128, nframes);
gain_t delta, initial, target;
double fractional_shift = -1.0/(declick-1);
double fractional_pos;
const framecnt_t declick = std::min ((framecnt_t) 512, nframes);
const double fractional_shift = 1.0 / declick ;
gain_t delta, initial;
if (dir < 0) {
/* fade out: remove more and more of delta from initial */
delta = -1.0;
initial = 1.0;
target = 0.0;
} else {
/* fade in: add more and more of delta from initial */
delta = 1.0;
initial = 0.0;
target = 1.0;
}
/* Audio Gain */
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
Sample* const buffer = i->data();
fractional_pos = 1.0;
double fractional_pos = 0.0;
for (pframes_t nx = 0; nx < declick; ++nx) {
buffer[nx] *= (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
buffer[nx] *= initial + (delta * fractional_pos);
fractional_pos += fractional_shift;
}
/* now ensure the rest of the buffer has the target value applied, if necessary. */
if (declick != nframes) {
if (target == 0.0) {
if (dir < 0) {
memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
} else if (target != 1.0) {
apply_gain_to_buffer (&buffer[declick], nframes - declick, target);
}
}
}
}
void
Amp::apply_gain (AudioBuffer& buf, framecnt_t nframes, gain_t initial, gain_t target)
gain_t
Amp::apply_gain (AudioBuffer& buf, framecnt_t sample_rate, framecnt_t nframes, gain_t initial, gain_t target)
{
/** Apply a (potentially) declicked gain to the contents of @a buf
/* Apply a (potentially) declicked gain to the contents of @a buf
* -- used by MonitorProcessor::run()
*/
if (nframes == 0) {
return;
return initial;
}
// if we don't need to declick, defer to apply_simple_gain
if (initial == target) {
apply_simple_gain (buf, nframes, target);
return;
return target;
}
const framecnt_t declick = std::min ((framecnt_t) 128, nframes);
gain_t delta;
double fractional_shift = -1.0/declick;
double fractional_pos;
if (target < initial) {
/* fade out: remove more and more of delta from initial */
delta = -(initial - target);
} else {
/* fade in: add more and more of delta from initial */
delta = target - initial;
}
Sample* const buffer = buf.data();
const float a = 62.78 / sample_rate; // 10 Hz LPF, see [other] Amp::apply_gain() above,
fractional_pos = 1.0;
for (pframes_t nx = 0; nx < declick; ++nx) {
buffer[nx] *= (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
fractional_pos += fractional_shift;
float lpf = initial;
for (pframes_t nx = 0; nx < nframes; ++nx) {
buffer[nx] *= lpf;
lpf += a * (target - lpf);
}
/* now ensure the rest of the buffer has the target value applied, if necessary. */
if (declick != nframes) {
if (target == 0.0) {
memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
} else if (target != 1.0) {
apply_gain_to_buffer (&buffer[declick], nframes - declick, target);
}
}
if (lpf < 1e-10) return 0;
if (fabsf(lpf - 1.0) < 1e-10) return 1.0;
return lpf;
}
void
@ -432,7 +405,7 @@ Amp::GainControl::user_to_internal (double u) const
std::string
Amp::GainControl::get_user_string () const
{
char theBuf[32]; sprintf( theBuf, "%3.1f dB", accurate_coefficient_to_dB (get_value()));
char theBuf[32]; sprintf( theBuf, _("%3.1f dB"), accurate_coefficient_to_dB (get_value()));
return std::string(theBuf);
}
@ -452,8 +425,13 @@ Amp::setup_gain_automation (framepos_t start_frame, framepos_t end_frame, framec
assert (_gain_automation_buffer);
_apply_gain_automation = _gain_control->list()->curve().rt_safe_get_vector (
start_frame, end_frame, _gain_automation_buffer, nframes);
if (start_frame != _current_automation_frame) {
_current_gain = _gain_automation_buffer[0];
}
_current_automation_frame = end_frame;
} else {
_apply_gain_automation = false;
_current_automation_frame = INT64_MAX;
}
}
@ -468,7 +446,7 @@ Amp::value_as_string (boost::shared_ptr<AutomationControl> ac) const
{
if (ac == _gain_control) {
char buffer[32];
snprintf (buffer, sizeof (buffer), "%.2fdB", ac->internal_to_user (ac->get_value ()));
snprintf (buffer, sizeof (buffer), _("%.2fdB"), ac->internal_to_user (ac->get_value ()));
return buffer;
}

View file

@ -22,6 +22,10 @@
#include "ardour/session_event.h"
#include "ardour/transient_detector.h"
#include "pbd/compose.h"
#include "pbd/error.h"
#include "i18n.h"
using namespace std;
using namespace ARDOUR;
using namespace PBD;
@ -102,13 +106,16 @@ Analyser::analyse_audio_file_source (boost::shared_ptr<AudioFileSource> src)
{
AnalysisFeatureList results;
TransientDetector td (src->sample_rate());
if (td.run (src->get_transients_path(), src.get(), 0, results) == 0) {
src->set_been_analysed (true);
} else {
try {
TransientDetector td (src->sample_rate());
if (td.run (src->get_transients_path(), src.get(), 0, results) == 0) {
src->set_been_analysed (true);
} else {
src->set_been_analysed (false);
}
} catch (...) {
error << string_compose(_("Transient Analysis failed for %1."), _("Audio File Source")) << endmsg;;
src->set_been_analysed (false);
return;
}
}

View file

@ -59,10 +59,10 @@ public:
XMLNode& state (bool full);
int set_state (const XMLNode&, int version);
static void apply_gain (BufferSet& bufs, framecnt_t nframes, gain_t initial, gain_t target);
static gain_t apply_gain (BufferSet& bufs, framecnt_t sample_rate, framecnt_t nframes, gain_t initial, gain_t target);
static void apply_simple_gain(BufferSet& bufs, framecnt_t nframes, gain_t target);
static void apply_gain (AudioBuffer& buf, framecnt_t nframes, gain_t initial, gain_t target);
static gain_t apply_gain (AudioBuffer& buf, framecnt_t sample_rate, framecnt_t nframes, gain_t initial, gain_t target);
static void apply_simple_gain(AudioBuffer& buf, framecnt_t nframes, gain_t target);
static void declick (BufferSet& bufs, framecnt_t nframes, int dir);
@ -111,6 +111,7 @@ private:
bool _apply_gain;
bool _apply_gain_automation;
float _current_gain;
framepos_t _current_automation_frame;
boost::shared_ptr<GainControl> _gain_control;

View file

@ -51,6 +51,7 @@ namespace ARDOUR {
extern LIBARDOUR_API PBD::Signal3<void,std::string,std::string,bool> PluginScanMessage;
extern LIBARDOUR_API PBD::Signal1<void,int> PluginScanTimeout;
extern LIBARDOUR_API PBD::Signal0<void> GUIIdle;
extern LIBARDOUR_API PBD::Signal3<bool,std::string,std::string,int> CopyConfigurationFiles;
/**
* @param with_vst true to enable VST Support
@ -81,6 +82,14 @@ namespace ARDOUR {
LIBARDOUR_API void setup_fpu ();
LIBARDOUR_API std::vector<SyncSource> get_available_sync_options();
/* the @param ui_handler will be called if there are old configuration
* files to be copied. It should (probably) ask the user about the
* action, and return true or false depending on whether or not the
* copy should take place.
*/
LIBARDOUR_API void check_for_old_configuration_files ();
LIBARDOUR_API int handle_old_configuration_files (boost::function<bool (std::string const&, std::string const&, int)> ui_handler);
}
#endif /* __ardour_ardour_h__ */

View file

@ -186,7 +186,7 @@ class LIBARDOUR_API AudioBackend : public PortEngine {
* if there is any chance that a buffer size of 1024 is not in the list
* returned by available_buffer_sizes()
*/
virtual uint32_t default_buffer_size () const {
virtual uint32_t default_buffer_size (const std::string& device) const {
return 1024;
}
@ -477,12 +477,12 @@ class LIBARDOUR_API AudioBackend : public PortEngine {
*
* Can be called from any thread.
*/
virtual pframes_t sample_time () = 0;
virtual framepos_t sample_time () = 0;
/** Return the time according to the sample clock in use when the most
* recent buffer process cycle began. Can be called from any thread.
*/
virtual pframes_t sample_time_at_cycle_start () = 0;
virtual framepos_t sample_time_at_cycle_start () = 0;
/** Return the time since the current buffer process cycle started,
* in samples, according to the sample clock in use.

View file

@ -125,7 +125,6 @@ class LIBARDOUR_API AudioDiskstream : public Diskstream
}
}
CubicInterpolation interpolation;
protected:
friend class Session;
@ -205,6 +204,8 @@ class LIBARDOUR_API AudioDiskstream : public Diskstream
typedef std::vector<ChannelInfo*> ChannelList;
CubicInterpolation interpolation;
/* The two central butler operations */
int do_flush (RunContext context, bool force = false);
int do_refill () { return _do_refill(_mixdown_buffer, _gain_buffer); }

View file

@ -74,7 +74,7 @@ class LIBARDOUR_API AudioEngine : public SessionHandlePtr, public PortManager
bool setup_required () const;
ProcessThread* main_thread() const { return _main_thread; }
/* START BACKEND PROXY API
*
* See audio_backend.h for full documentation and semantics. These wrappers
@ -94,8 +94,8 @@ class LIBARDOUR_API AudioEngine : public SessionHandlePtr, public PortManager
pframes_t samples_per_cycle () const;
int usecs_per_cycle () const;
size_t raw_buffer_size (DataType t);
pframes_t sample_time ();
pframes_t sample_time_at_cycle_start ();
framepos_t sample_time ();
framepos_t sample_time_at_cycle_start ();
pframes_t samples_since_cycle_start ();
bool get_sync_offset (pframes_t& offset) const;
@ -104,8 +104,10 @@ class LIBARDOUR_API AudioEngine : public SessionHandlePtr, public PortManager
bool in_process_thread ();
uint32_t process_thread_count ();
int backend_reset_requested();
void request_backend_reset();
void request_device_list_update();
void launch_device_control_app();
bool is_realtime() const;
bool connected() const;
@ -185,6 +187,12 @@ class LIBARDOUR_API AudioEngine : public SessionHandlePtr, public PortManager
PBD::Signal0<void> Running;
PBD::Signal0<void> Stopped;
/* these two are emitted when a device reset is initiated/finished
*/
PBD::Signal0<void> DeviceResetStarted;
PBD::Signal0<void> DeviceResetFinished;
static AudioEngine* instance() { return _instance; }
static void destroy();
void died ();
@ -224,6 +232,16 @@ class LIBARDOUR_API AudioEngine : public SessionHandlePtr, public PortManager
LatencyMeasurement measuring_latency () const { return _measuring_latency; }
/* These two are used only in builds where SILENCE_AFTER_SECONDS was
* set. BecameSilent will be emitted when the audioengine goes silent.
* reset_silence_countdown() can be used to reset the silence
* countdown, whose duration will be reduced to half of its previous
* value.
*/
PBD::Signal0<void> BecameSilent;
void reset_silence_countdown ();
private:
AudioEngine ();
@ -285,6 +303,12 @@ class LIBARDOUR_API AudioEngine : public SessionHandlePtr, public PortManager
BackendMap _backends;
AudioBackendInfo* backend_discover (const std::string&);
void drop_backend ();
#ifdef SILENCE_AFTER
framecnt_t _silence_countdown;
uint32_t _silence_hit_cnt;
#endif
};
} // namespace ARDOUR

View file

@ -28,6 +28,7 @@
#include <glibmm/threads.h>
#include <boost/function.hpp>
#include <boost/scoped_array.hpp>
#include "ardour/source.h"
#include "ardour/ardour.h"
@ -164,6 +165,12 @@ class LIBARDOUR_API AudioSource : virtual public Source,
framecnt_t peak_leftover_size;
Sample* peak_leftovers;
framepos_t peak_leftover_frame;
mutable bool _first_run;
mutable double _last_scale;
mutable off_t _last_map_off;
mutable size_t _last_raw_map_length;
mutable boost::scoped_array<PeakData> peak_cache;
};
}

View file

@ -48,6 +48,7 @@ class LIBARDOUR_API AutomationWatch : public sigc::trackable, public ARDOUR::Ses
static AutomationWatch* _instance;
Glib::Threads::Thread* _thread;
framepos_t _last_time;
bool _run_thread;
AutomationWatches automation_watches;
Glib::Threads::Mutex automation_watch_lock;

View file

@ -37,15 +37,15 @@ class TempoMap;
* them to the opposite unit, taking tempo changes into account.
*/
class LIBARDOUR_API BeatsFramesConverter
: public Evoral::TimeConverter<Evoral::MusicalTime,framepos_t> {
: public Evoral::TimeConverter<Evoral::Beats,framepos_t> {
public:
BeatsFramesConverter (TempoMap& tempo_map, framepos_t origin)
: Evoral::TimeConverter<Evoral::MusicalTime, framepos_t> (origin)
: Evoral::TimeConverter<Evoral::Beats, framepos_t> (origin)
, _tempo_map(tempo_map)
{}
framepos_t to (Evoral::MusicalTime beats) const;
Evoral::MusicalTime from (framepos_t frames) const;
framepos_t to (Evoral::Beats beats) const;
Evoral::Beats from (framepos_t frames) const;
private:
TempoMap& _tempo_map;

View file

@ -28,6 +28,7 @@
#include "pbd/glib_semaphore.h"
#endif
#include "pbd/crossthread.h"
#include "pbd/ringbuffer.h"
#include "pbd/pool.h"
#include "ardour/libardour_visibility.h"
@ -86,38 +87,17 @@ class LIBARDOUR_API Butler : public SessionHandleRef
uint32_t midi_dstream_buffer_size;
RingBuffer<CrossThreadPool*> pool_trash;
#ifdef PLATFORM_WINDOWS
PBD::atomic_counter m_request_state;
PBD::GlibSemaphore m_request_sem;
#else
int request_pipe[2];
#endif
private:
void empty_pool_trash ();
void config_changed (std::string);
#ifndef PLATFORM_WINDOWS
int setup_request_pipe ();
#endif
/**
* return true if there are requests to be processed
*/
bool wait_for_requests ();
/**
* Remove request from butler request queue
*
* return true if there was another request and req is valid
*/
bool dequeue_request (Request::Type& req);
/**
* Add request to butler thread request queue
*/
void queue_request (Request::Type r);
CrossThreadChannel _xthread;
};
} // namespace ARDOUR

View file

@ -40,7 +40,6 @@ namespace ARDOUR {
LIBARDOUR_API extern const char* const route_templates_dir_name;
LIBARDOUR_API extern const char* const surfaces_dir_name;
LIBARDOUR_API extern const char* const ladspa_dir_name;
LIBARDOUR_API extern const char* const user_config_dir_name;
LIBARDOUR_API extern const char* const panner_dir_name;
LIBARDOUR_API extern const char* const backend_dir_name;

View file

@ -138,8 +138,12 @@ class LIBARDOUR_API Diskstream : public SessionObject, public PublicDiskstream
ChanCount n_channels() { return _n_channels; }
static framecnt_t disk_io_frames() { return disk_io_chunk_frames; }
static void set_disk_io_chunk_frames (framecnt_t n) { disk_io_chunk_frames = n; }
static framecnt_t disk_read_frames() { return disk_read_chunk_frames; }
static framecnt_t disk_write_frames() { return disk_write_chunk_frames; }
static void set_disk_read_chunk_frames (framecnt_t n) { disk_read_chunk_frames = n; }
static void set_disk_write_chunk_frames (framecnt_t n) { disk_write_chunk_frames = n; }
static framecnt_t default_disk_read_chunk_frames ();
static framecnt_t default_disk_write_chunk_frames ();
/* Stateful */
virtual XMLNode& get_state(void);
@ -268,7 +272,9 @@ class LIBARDOUR_API Diskstream : public SessionObject, public PublicDiskstream
framecnt_t& rec_nframes, framecnt_t& rec_offset
);
static framecnt_t disk_io_chunk_frames;
static framecnt_t disk_read_chunk_frames;
static framecnt_t disk_write_chunk_frames;
std::vector<CaptureInfo*> capture_info;
mutable Glib::Threads::Mutex capture_info_lock;

View file

@ -54,14 +54,12 @@ public:
void set_descriptor(const Evoral::Parameter& param,
const Evoral::ParameterDescriptor& desc);
URIMap& uri_map() { return _uri_map; }
private:
typedef std::map<Evoral::Parameter, Evoral::ParameterDescriptor> Descriptors;
EventTypeMap(URIMap& uri_map) : _uri_map(uri_map) {}
EventTypeMap(URIMap* uri_map) : _uri_map(uri_map) {}
URIMap& _uri_map;
URIMap* _uri_map;
Descriptors _descriptors;
static EventTypeMap* event_type_map;

View file

@ -27,11 +27,16 @@
namespace ARDOUR {
/**
* @return the path to the directory used to store user specific ardour
* configuration files.
* @post user_config_directory() exists
* @return the path to the directory used to store user specific
* configuration files for the given @param version of the program.
* If @param version is negative, the build-time string PROGRAM_VERSION
* will be used to determine the version number.
*
* @post user_config_directory() exists IF version was negative.
*
*
*/
LIBARDOUR_API std::string user_config_directory ();
LIBARDOUR_API std::string user_config_directory (int version = -1);
/**
* @return the path to the directory used to store user specific
@ -40,6 +45,14 @@ namespace ARDOUR {
*/
LIBARDOUR_API std::string user_cache_directory ();
/**
* @return the path used to store a persistent indication
* that the given version of the program has been used before.
*
* @param version is the version to check for. If unspecified,
* it defaults to the current (build-time) version of the program.
*/
LIBARDOUR_API std::string been_here_before_path (int version = -1);
/**
* @return the path to the directory that contains the system wide ardour

View file

@ -89,7 +89,7 @@ protected:
virtual void session_going_away ();
private:
volatile bool _quit_threads;
volatile bool _threads_active;
void reset_thread_list ();
void drop_threads ();
@ -136,6 +136,10 @@ private:
bool _process_noroll;
int _process_retval;
bool _process_need_butler;
// enginer / thread connection
PBD::ScopedConnectionList engine_connections;
void engine_stopped ();
};
} // namespace

View file

@ -68,6 +68,13 @@ public:
framecnt_t interpolate (int channel, framecnt_t nframes, Sample* input, Sample* output);
};
class BufferSet;
class LIBARDOUR_API CubicMidiInterpolation : public Interpolation {
public:
framecnt_t distance (framecnt_t nframes, bool roll = true);
};
} // namespace ARDOUR
#endif

View file

@ -39,10 +39,10 @@ public:
Legatize(bool shrink_only);
~Legatize();
typedef Evoral::Sequence<Evoral::MusicalTime>::Notes Notes;
typedef Evoral::Sequence<Evoral::Beats>::Notes Notes;
Command* operator()(boost::shared_ptr<ARDOUR::MidiModel> model,
Evoral::MusicalTime position,
Evoral::Beats position,
std::vector<Notes>& seqs);
std::string name() const { return std::string ("legatize"); }

View file

@ -0,0 +1,13 @@
#include "math.h"
#if defined __DARWIN_NO_LONG_LONG && defined MAC_OS_X_VERSION_MIN_REQUIRED && MAC_OS_X_VERSION_MIN_REQUIRED <= 1040
static inline long long int llrint (double x)
{
return (long long int)rint (x);
}
static inline long long int llrintf (float x)
{
return (long long int)rintf (x);
}
#endif

View file

@ -0,0 +1,97 @@
/*
Copyright (C) 2006-2015 Paul Davis
Author: David Robillard
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_channel_filter_h__
#define __ardour_channel_filter_h__
#include <stdint.h>
#include <glib.h>
#include "ardour/types.h"
#include "pbd/signals.h"
namespace ARDOUR
{
class BufferSet;
/** Filter/mapper for MIDI channels.
*
* Channel mapping is configured by setting a mode and "mask", where the
* meaning of the mask depends on the mode.
*
* If mode is FilterChannels, each mask bit represents a midi channel (bit 0 =
* channel 0, bit 1 = channel 1, ...). Only events whose channel corresponds
* to a 1 bit will be passed.
*
* If mode is ForceChannel, mask is simply a channel number which all events
* will be forced to.
*/
class LIBARDOUR_API MidiChannelFilter
{
public:
MidiChannelFilter();
/** Filter `bufs` in-place. */
void filter(BufferSet& bufs);
/** Filter/map a MIDI message by channel.
*
* May modify the channel in `buf` if necessary.
*
* @return true if this event should be filtered out.
*/
bool filter(uint8_t* buf, uint32_t len);
/** Atomically set the channel mode and corresponding mask.
* @return true iff configuration changed.
*/
bool set_channel_mode(ChannelMode mode, uint16_t mask);
/** Atomically set the channel mask for the current mode.
* @return true iff configuration changed.
*/
bool set_channel_mask(uint16_t mask);
/** Atomically get both the channel mode and mask. */
void get_mode_and_mask(ChannelMode* mode, uint16_t* mask) const {
const uint32_t mm = g_atomic_int_get(&_mode_mask);
*mode = static_cast<ChannelMode>((mm & 0xFFFF0000) >> 16);
*mask = (mm & 0x0000FFFF);
}
ChannelMode get_channel_mode() const {
return static_cast<ChannelMode>((g_atomic_int_get(&_mode_mask) & 0xFFFF0000) >> 16);
}
uint16_t get_channel_mask() const {
return g_atomic_int_get(&_mode_mask) & 0x0000FFFF;
}
PBD::Signal0<void> ChannelMaskChanged;
PBD::Signal0<void> ChannelModeChanged;
private:
uint32_t _mode_mask; ///< 16 bits mode, 16 bits mask
};
} /* namespace ARDOUR */
#endif /* __ardour_channel_filter_h__ */

View file

@ -38,6 +38,7 @@
#include "ardour/diskstream.h"
#include "ardour/midi_buffer.h"
#include "ardour/utils.h"
#include "ardour/interpolation.h"
struct tm;
@ -71,6 +72,7 @@ class LIBARDOUR_API MidiDiskstream : public Diskstream
void set_record_enabled (bool yn);
void reset_tracker ();
void resolve_tracker (Evoral::EventSink<framepos_t>& buffer, framepos_t time);
boost::shared_ptr<MidiPlaylist> midi_playlist ();
@ -186,6 +188,8 @@ class LIBARDOUR_API MidiDiskstream : public Diskstream
*/
MidiBuffer _gui_feed_buffer;
mutable Glib::Threads::Mutex _gui_feed_buffer_mutex;
CubicMidiInterpolation interpolation;
};
}; /* namespace ARDOUR */

View file

@ -52,9 +52,9 @@ class MidiSource;
* Because of this MIDI controllers and automatable controllers/widgets/etc
* are easily interchangeable.
*/
class LIBARDOUR_API MidiModel : public AutomatableSequence<Evoral::MusicalTime> {
class LIBARDOUR_API MidiModel : public AutomatableSequence<Evoral::Beats> {
public:
typedef Evoral::MusicalTime TimeType;
typedef Evoral::Beats TimeType;
MidiModel (boost::shared_ptr<MidiSource>);
@ -126,7 +126,6 @@ public:
static Variant::Type value_type (Property prop);
private:
struct NoteChange {
NoteDiffCommand::Property property;
NotePtr note;
@ -135,12 +134,17 @@ public:
Variant new_value;
};
typedef std::list<NoteChange> ChangeList;
ChangeList _changes;
typedef std::list<NoteChange> ChangeList;
typedef std::list< boost::shared_ptr< Evoral::Note<TimeType> > > NoteList;
NoteList _added_notes;
NoteList _removed_notes;
const ChangeList& changes() const { return _changes; }
const NoteList& added_notes() const { return _added_notes; }
const NoteList& removed_notes() const { return _removed_notes; }
private:
ChangeList _changes;
NoteList _added_notes;
NoteList _removed_notes;
std::set<NotePtr> side_effect_removals;
@ -259,8 +263,8 @@ public:
bool write_section_to(boost::shared_ptr<MidiSource> source,
const Glib::Threads::Mutex::Lock& source_lock,
Evoral::MusicalTime begin = Evoral::MinMusicalTime,
Evoral::MusicalTime end = Evoral::MaxMusicalTime);
Evoral::Beats begin = Evoral::MinBeats,
Evoral::Beats end = Evoral::MaxBeats);
// MidiModel doesn't use the normal AutomationList serialisation code
// since controller data is stored in the .mid
@ -285,6 +289,8 @@ public:
void insert_silence_at_start (TimeType);
void transpose (TimeType, TimeType, int);
std::set<WeakNotePtr>& active_notes() { return _active_notes; }
protected:
int resolve_overlaps_unlocked (const NotePtr, void* arg = 0);
@ -302,7 +308,6 @@ private:
public:
WriteLock edit_lock();
WriteLock write_lock();
private:
friend class DeltaCommand;
@ -319,6 +324,8 @@ private:
// We cannot use a boost::shared_ptr here to avoid a retain cycle
boost::weak_ptr<MidiSource> _midi_source;
InsertMergePolicy _insert_merge_policy;
std::set<WeakNotePtr> _active_notes;
};
} /* namespace ARDOUR */

View file

@ -38,8 +38,8 @@ class LIBARDOUR_API MidiOperator {
virtual ~MidiOperator() {}
virtual Command* operator() (boost::shared_ptr<ARDOUR::MidiModel>,
Evoral::MusicalTime,
std::vector<Evoral::Sequence<Evoral::MusicalTime>::Notes>&) = 0;
Evoral::Beats,
std::vector<Evoral::Sequence<Evoral::Beats>::Notes>&) = 0;
virtual std::string name() const = 0;
};

View file

@ -126,10 +126,11 @@ public:
std::list<std::string> custom_device_mode_names_by_model(std::string model_name) {
if (model_name != "") {
return master_device_by_model(model_name)->custom_device_mode_names();
} else {
return std::list<std::string>();
if (master_device_by_model(model_name)) {
return master_device_by_model(model_name)->custom_device_mode_names();
}
}
return std::list<std::string>();
}
const MasterDeviceNames::Models& all_models() const { return _all_models; }

View file

@ -23,8 +23,15 @@
#include <vector>
#include <list>
#include <boost/utility.hpp>
#include "ardour/ardour.h"
#include "ardour/midi_model.h"
#include "ardour/midi_state_tracker.h"
#include "ardour/note_fixer.h"
#include "ardour/playlist.h"
#include "evoral/Beats.hpp"
#include "evoral/Note.hpp"
#include "evoral/Parameter.hpp"
namespace Evoral {
@ -34,10 +41,11 @@ template<typename Time> class EventSink;
namespace ARDOUR
{
class Session;
class BeatsFramesConverter;
class MidiChannelFilter;
class MidiRegion;
class Session;
class Source;
class MidiStateTracker;
template<typename T> class MidiRingBuffer;
@ -47,13 +55,31 @@ public:
MidiPlaylist (Session&, const XMLNode&, bool hidden = false);
MidiPlaylist (Session&, std::string name, bool hidden = false);
MidiPlaylist (boost::shared_ptr<const MidiPlaylist> other, std::string name, bool hidden = false);
MidiPlaylist (boost::shared_ptr<const MidiPlaylist> other, framepos_t start, framecnt_t cnt,
std::string name, bool hidden = false);
/** This constructor does NOT notify others (session) */
MidiPlaylist (boost::shared_ptr<const MidiPlaylist> other,
framepos_t start,
framecnt_t cnt,
std::string name,
bool hidden = false);
~MidiPlaylist ();
/** Read a range from the playlist into an event sink.
*
* @param buf Destination for events.
* @param start First frame of read range.
* @param cnt Number of frames in read range.
* @param chan_n Must be 0 (this is the audio-style "channel", where each
* channel is backed by a separate region, not MIDI channels, which all
* exist in the same region and are not handled here).
* @return The number of frames read (time, not an event count).
*/
framecnt_t read (Evoral::EventSink<framepos_t>& buf,
framepos_t start, framecnt_t cnt, uint32_t chan_n = 0);
framepos_t start,
framecnt_t cnt,
uint32_t chan_n = 0,
MidiChannelFilter* filter = NULL);
int set_state (const XMLNode&, int version);
@ -63,6 +89,15 @@ public:
std::set<Evoral::Parameter> contained_automation();
/** Handle a region edit during read.
*
* This must be called before the command is applied to the model. Events
* are injected into the playlist output to compensate for edits to active
* notes and maintain coherent output and tracker state.
*/
void region_edited(boost::shared_ptr<Region> region,
const MidiModel::NoteDiffCommand* cmd);
/** Clear all note trackers. */
void reset_note_trackers ();
@ -74,19 +109,24 @@ public:
void resolve_note_trackers (Evoral::EventSink<framepos_t>& dst, framepos_t time);
protected:
void remove_dependents (boost::shared_ptr<Region> region);
private:
typedef Evoral::Note<Evoral::Beats> Note;
typedef Evoral::Event<framepos_t> Event;
struct RegionTracker : public boost::noncopyable {
MidiStateTracker tracker; ///< Active note tracker
NoteFixer fixer; ///< Edit compensation
};
typedef std::map< Region*, boost::shared_ptr<RegionTracker> > NoteTrackers;
void dump () const;
bool region_changed (const PBD::PropertyChange&, boost::shared_ptr<Region>);
NoteMode _note_mode;
typedef std::map<Region*,MidiStateTracker*> NoteTrackers;
NoteTrackers _note_trackers;
NoteMode _note_mode;
framepos_t _read_end;
};
} /* namespace ARDOUR */

View file

@ -45,7 +45,7 @@ public:
XMLNode& get_state ();
int set_state (const XMLNode&, int version);
void append_event_beats(const Glib::Threads::Mutex::Lock& lock, const Evoral::Event<Evoral::MusicalTime>& ev);
void append_event_beats(const Glib::Threads::Mutex::Lock& lock, const Evoral::Event<Evoral::Beats>& ev);
void append_event_frames(const Glib::Threads::Mutex::Lock& lock, const Evoral::Event<framepos_t>& ev, framepos_t source_start);
void load_model(const Glib::Threads::Mutex::Lock& lock, bool force_reload=false);
void destroy_model(const Glib::Threads::Mutex::Lock& lock);
@ -65,7 +65,8 @@ protected:
framepos_t position,
framepos_t start,
framecnt_t cnt,
MidiStateTracker* tracker) const;
MidiStateTracker* tracker,
MidiChannelFilter* filter) const;
framecnt_t write_unlocked (const Lock& lock,
MidiRingBuffer<framepos_t>& dst,

View file

@ -56,6 +56,8 @@ class LIBARDOUR_API MidiPort : public Port {
MidiBuffer& get_midi_buffer (pframes_t nframes);
void set_always_parse (bool yn);
void set_trace_on (bool yn);
MIDI::Parser& self_parser() { return _self_parser; }
protected:
@ -69,7 +71,8 @@ class LIBARDOUR_API MidiPort : public Port {
bool _resolve_required;
bool _input_active;
bool _always_parse;
bool _trace_on;
/* Naming this is tricky. AsyncMIDIPort inherits (for now, aug 2013) from
* both MIDI::Port, which has _parser, and this (ARDOUR::MidiPort). We
* need parsing support in this object, independently of what the

View file

@ -32,13 +32,8 @@ class XMLNode;
namespace ARDOUR {
namespace Properties {
/* this is pseudo-property: nothing has this as an actual
property, but it allows us to signal changes to the
MidiModel used by the MidiRegion
*/
LIBARDOUR_API extern PBD::PropertyDescriptor<void*> midi_data;
LIBARDOUR_API extern PBD::PropertyDescriptor<Evoral::MusicalTime> start_beats;
LIBARDOUR_API extern PBD::PropertyDescriptor<Evoral::MusicalTime> length_beats;
LIBARDOUR_API extern PBD::PropertyDescriptor<Evoral::Beats> start_beats;
LIBARDOUR_API extern PBD::PropertyDescriptor<Evoral::Beats> length_beats;
}
}
@ -48,13 +43,14 @@ template<typename Time> class EventSink;
namespace ARDOUR {
class Route;
class Playlist;
class Session;
class MidiChannelFilter;
class MidiFilter;
class MidiModel;
class MidiSource;
class MidiStateTracker;
class Playlist;
class Route;
class Session;
template<typename T> class MidiRingBuffer;
@ -79,7 +75,8 @@ class LIBARDOUR_API MidiRegion : public Region
framecnt_t dur,
uint32_t chan_n = 0,
NoteMode mode = Sustained,
MidiStateTracker* tracker = 0) const;
MidiStateTracker* tracker = 0,
MidiChannelFilter* filter = 0) const;
framecnt_t master_read_at (MidiRingBuffer<framepos_t>& dst,
framepos_t position,
@ -114,8 +111,8 @@ class LIBARDOUR_API MidiRegion : public Region
private:
friend class RegionFactory;
PBD::Property<Evoral::MusicalTime> _start_beats;
PBD::Property<Evoral::MusicalTime> _length_beats;
PBD::Property<Evoral::Beats> _start_beats;
PBD::Property<Evoral::Beats> _length_beats;
MidiRegion (const SourceList&);
MidiRegion (boost::shared_ptr<const MidiRegion>);
@ -126,7 +123,8 @@ class LIBARDOUR_API MidiRegion : public Region
framecnt_t dur,
uint32_t chan_n = 0,
NoteMode mode = Sustained,
MidiStateTracker* tracker = 0) const;
MidiStateTracker* tracker = 0,
MidiChannelFilter* filter = 0) const;
void register_properties ();
void post_set (const PBD::PropertyChange&);
@ -141,7 +139,6 @@ class LIBARDOUR_API MidiRegion : public Region
void model_changed ();
void model_automation_state_changed (Evoral::Parameter const &);
void model_contents_changed ();
void set_start_beats_from_start_frames ();
void update_after_tempo_map_change ();

View file

@ -49,12 +49,14 @@ public:
inline bool read_contents(uint32_t size, uint8_t* buf);
size_t read(MidiBuffer& dst, framepos_t start, framepos_t end, framecnt_t offset=0, bool stop_on_overflow_in_destination=false);
size_t skip_to(framepos_t start);
void dump(std::ostream& dst);
void flush (framepos_t start, framepos_t end);
void reset_tracker ();
void resolve_tracker (MidiBuffer& dst, framepos_t);
void resolve_tracker (Evoral::EventSink<framepos_t>& dst, framepos_t);
private:
MidiStateTracker _tracker;

View file

@ -34,6 +34,7 @@
namespace ARDOUR {
class MidiChannelFilter;
class MidiStateTracker;
class MidiModel;
@ -43,7 +44,7 @@ template<typename T> class MidiRingBuffer;
class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_shared_from_this<MidiSource>
{
public:
typedef Evoral::MusicalTime TimeType;
typedef Evoral::Beats TimeType;
MidiSource (Session& session, std::string name, Source::Flag flags = Source::Flag(0));
MidiSource (Session& session, const XMLNode&);
@ -59,8 +60,8 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
*/
int write_to (const Lock& lock,
boost::shared_ptr<MidiSource> newsrc,
Evoral::MusicalTime begin = Evoral::MinMusicalTime,
Evoral::MusicalTime end = Evoral::MaxMusicalTime);
Evoral::Beats begin = Evoral::MinBeats,
Evoral::Beats end = Evoral::MaxBeats);
/** Read the data in a given time range from the MIDI source.
* All time stamps in parameters are in audio frames (even if the source has tempo time).
@ -77,6 +78,7 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
framepos_t start,
framecnt_t cnt,
MidiStateTracker* tracker,
MidiChannelFilter* filter,
const std::set<Evoral::Parameter>& filtered) const;
/** Write data from a MidiRingBuffer to this source.
@ -93,8 +95,8 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
*
* Caller must ensure that the event is later than the last written event.
*/
virtual void append_event_beats(const Lock& lock,
const Evoral::Event<Evoral::MusicalTime>& ev) = 0;
virtual void append_event_beats(const Lock& lock,
const Evoral::Event<Evoral::Beats>& ev) = 0;
/** Append a single event with a timestamp in frames.
*
@ -132,9 +134,9 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
* etc.
*/
virtual void mark_midi_streaming_write_completed (
const Lock& lock,
Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption stuck_option,
Evoral::MusicalTime when = Evoral::MusicalTime());
const Lock& lock,
Evoral::Sequence<Evoral::Beats>::StuckNoteOption stuck_option,
Evoral::Beats when = Evoral::Beats());
virtual void session_saved();
@ -154,8 +156,12 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
virtual void load_model(const Glib::Threads::Mutex::Lock& lock, bool force_reload=false) = 0;
virtual void destroy_model(const Glib::Threads::Mutex::Lock& lock) = 0;
/** Reset cached information (like iterators) when things have changed. */
void invalidate(const Glib::Threads::Mutex::Lock& lock);
/** Reset cached information (like iterators) when things have changed.
* @param lock Source lock, which must be held by caller.
* @param notes If non-NULL, currently active notes are added to this set.
*/
void invalidate(const Glib::Threads::Mutex::Lock& lock,
std::set<Evoral::Sequence<Evoral::Beats>::WeakNotePtr>* notes=NULL);
void set_note_mode(const Glib::Threads::Mutex::Lock& lock, NoteMode mode);
@ -188,7 +194,8 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
framepos_t position,
framepos_t start,
framecnt_t cnt,
MidiStateTracker* tracker) const = 0;
MidiStateTracker* tracker,
MidiChannelFilter* filter) const = 0;
/** Write data to this source from a MidiRingBuffer.
* @param source Buffer to read from.
@ -205,11 +212,11 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
boost::shared_ptr<MidiModel> _model;
bool _writing;
mutable Evoral::Sequence<Evoral::MusicalTime>::const_iterator _model_iter;
mutable bool _model_iter_valid;
mutable Evoral::Sequence<Evoral::Beats>::const_iterator _model_iter;
mutable bool _model_iter_valid;
mutable Evoral::MusicalTime _length_beats;
mutable framepos_t _last_read_end;
mutable Evoral::Beats _length_beats;
mutable framepos_t _last_read_end;
/** The total duration of the current capture. */
framepos_t _capture_length;

View file

@ -46,7 +46,7 @@ public:
void remove (uint8_t note, uint8_t chn);
void resolve_notes (MidiBuffer& buffer, framepos_t time);
void resolve_notes (Evoral::EventSink<framepos_t>& buffer, framepos_t time);
void resolve_notes (MidiSource& src, const Glib::Threads::Mutex::Lock& lock, Evoral::MusicalTime time);
void resolve_notes (MidiSource& src, const Glib::Threads::Mutex::Lock& lock, Evoral::Beats time);
void dump (std::ostream&);
void reset ();
bool empty() const { return _on == 0; }

View file

@ -20,10 +20,9 @@
#ifndef __ardour_midi_track_h__
#define __ardour_midi_track_h__
#include "pbd/ffs.h"
#include "ardour/track.h"
#include "ardour/midi_channel_filter.h"
#include "ardour/midi_ring_buffer.h"
#include "ardour/track.h"
namespace ARDOUR
{
@ -47,6 +46,7 @@ public:
void realtime_handle_transport_stopped ();
void realtime_locate ();
void non_realtime_locate (framepos_t);
boost::shared_ptr<Diskstream> create_diskstream ();
void set_diskstream (boost::shared_ptr<Diskstream>);
@ -108,38 +108,22 @@ public:
boost::shared_ptr<SMFSource> write_source (uint32_t n = 0);
/** Channel filtering mode.
* @param mask If mode is FilterChannels, each bit represents a midi channel:
* bit 0 = channel 0, bit 1 = channel 1 etc. the read and write methods will only
* process events whose channel bit is 1.
* If mode is ForceChannel, mask is simply a channel number which all events will
* be forced to while reading.
*/
/* Configure capture/playback channels (see MidiChannelFilter). */
void set_capture_channel_mode (ChannelMode mode, uint16_t mask);
void set_playback_channel_mode (ChannelMode mode, uint16_t mask);
void set_playback_channel_mask (uint16_t mask);
void set_capture_channel_mask (uint16_t mask);
ChannelMode get_playback_channel_mode() const {
return static_cast<ChannelMode>((g_atomic_int_get(&_playback_channel_mask) & 0xffff0000) >> 16);
}
uint16_t get_playback_channel_mask() const {
return g_atomic_int_get(&_playback_channel_mask) & 0x0000ffff;
}
ChannelMode get_capture_channel_mode() const {
return static_cast<ChannelMode>((g_atomic_int_get(&_capture_channel_mask) & 0xffff0000) >> 16);
}
uint16_t get_capture_channel_mask() const {
return g_atomic_int_get(&_capture_channel_mask) & 0x0000ffff;
}
ChannelMode get_playback_channel_mode() const { return _playback_filter.get_channel_mode(); }
ChannelMode get_capture_channel_mode() const { return _capture_filter.get_channel_mode(); }
uint16_t get_playback_channel_mask() const { return _playback_filter.get_channel_mask(); }
uint16_t get_capture_channel_mask() const { return _capture_filter.get_channel_mask(); }
MidiChannelFilter& playback_filter() { return _playback_filter; }
MidiChannelFilter& capture_filter() { return _capture_filter; }
boost::shared_ptr<MidiPlaylist> midi_playlist ();
PBD::Signal0<void> PlaybackChannelMaskChanged;
PBD::Signal0<void> PlaybackChannelModeChanged;
PBD::Signal0<void> CaptureChannelMaskChanged;
PBD::Signal0<void> CaptureChannelModeChanged;
PBD::Signal1<void, boost::weak_ptr<MidiSource> > DataRecorded;
boost::shared_ptr<MidiBuffer> get_gui_feed_buffer () const;
@ -161,8 +145,8 @@ private:
NoteMode _note_mode;
bool _step_editing;
bool _input_active;
uint32_t _playback_channel_mask; // 16 bits mode, 16 bits mask
uint32_t _capture_channel_mask; // 16 bits mode, 16 bits mask
MidiChannelFilter _playback_filter;
MidiChannelFilter _capture_filter;
virtual boost::shared_ptr<Diskstream> diskstream_factory (XMLNode const &);
@ -183,31 +167,8 @@ private:
void track_input_active (IOChange, void*);
void map_input_active (bool);
void filter_channels (BufferSet& bufs, ChannelMode mode, uint32_t mask);
/* if mode is ForceChannel, force mask to the lowest set channel or 1 if no
* channels are set.
*/
#define force_mask(mode,mask) (((mode) == ForceChannel) ? (((mask) ? (1<<(PBD::ffs((mask))-1)) : 1)) : mask)
void _set_playback_channel_mode(ChannelMode mode, uint16_t mask) {
mask = force_mask (mode, mask);
g_atomic_int_set(&_playback_channel_mask, (uint32_t(mode) << 16) | uint32_t(mask));
}
void _set_playback_channel_mask (uint16_t mask) {
mask = force_mask (get_playback_channel_mode(), mask);
g_atomic_int_set(&_playback_channel_mask, (uint32_t(get_playback_channel_mode()) << 16) | uint32_t(mask));
}
void _set_capture_channel_mode(ChannelMode mode, uint16_t mask) {
mask = force_mask (mode, mask);
g_atomic_int_set(&_capture_channel_mask, (uint32_t(mode) << 16) | uint32_t(mask));
}
void _set_capture_channel_mask (uint16_t mask) {
mask = force_mask (get_capture_channel_mode(), mask);
g_atomic_int_set(&_capture_channel_mask, (uint32_t(get_capture_channel_mode()) << 16) | uint32_t(mask));
}
#undef force_mask
/** Update automation controls to reflect any changes in buffers. */
void update_controls (const BufferSet& bufs);
};
} /* namespace ARDOUR*/

View file

@ -0,0 +1,102 @@
/*
Copyright (C) 2015 Paul Davis
Author: David Robillard
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_note_fixer_h__
#define __ardour_note_fixer_h__
#include <list>
#include <boost/utility.hpp>
#include "ardour/midi_model.h"
#include "ardour/types.h"
#include "evoral/Beats.hpp"
#include "evoral/Note.hpp"
namespace Evoral { template<typename Time> class EventSink; }
namespace ARDOUR {
class BeatsFramesConverter;
class MidiStateTracker;
class TempoMap;
/** A tracker and compensator for note edit operations.
*
* This monitors edit operations sent to a model that affect active notes
* during a read, and maintains a queue of synthetic events that should be sent
* at the start of the next read to maintain coherent MIDI state.
*/
class NoteFixer : public boost::noncopyable
{
public:
typedef Evoral::Note<Evoral::Beats> Note;
~NoteFixer();
/** Clear all internal state. */
void clear();
/** Handle a region edit during read.
*
* This must be called before the command is applied to the model. Events
* are enqueued to compensate for edits which should be later sent with
* emit() at the start of the next read.
*
* @param cmd Command to compensate for.
* @param origin Timeline position of edited source.
* @param pos Current read position (last read end).
*/
void prepare(TempoMap& tempo_map,
const MidiModel::NoteDiffCommand* cmd,
framepos_t origin,
framepos_t pos,
std::set< boost::weak_ptr<Note> >& active_notes);
/** Emit any pending edit compensation events.
*
* @param dst Destination for events.
* @param pos Timestamp to be used for every event, should be the start of
* the read block immediately following any calls to prepare().
* @param tracker Tracker to update with emitted events.
*/
void emit(Evoral::EventSink<framepos_t>& dst,
framepos_t pos,
MidiStateTracker& tracker);
private:
typedef Evoral::Event<framepos_t> Event;
typedef std::list<Event*> Events;
/** Copy a beats event to a frames event with the given time stamp. */
Event* copy_event(framepos_t time, const Evoral::Event<Evoral::Beats>& ev);
/** Return true iff `note` is active at `pos`. */
bool note_is_active(const BeatsFramesConverter& converter,
boost::shared_ptr<Note> note,
framepos_t pos);
Events _events;
};
} /* namespace ARDOUR */
#endif /* __ardour_note_fixer_h__ */

View file

@ -24,6 +24,7 @@
#include <stdint.h>
#include "ardour/types.h"
#include "evoral/Parameter.hpp"
#include "evoral/midi_events.h"
namespace ARDOUR {
@ -54,6 +55,26 @@ midi_parameter_type(uint8_t status)
}
}
inline Evoral::Parameter
midi_parameter(const uint8_t* buf, const uint32_t len)
{
const uint8_t channel = buf[0] & 0x0F;
switch (midi_parameter_type(buf[0])) {
case MidiCCAutomation:
return Evoral::Parameter(MidiCCAutomation, channel, buf[1]);
case MidiPgmChangeAutomation:
return Evoral::Parameter(MidiPgmChangeAutomation, channel);
case MidiChannelPressureAutomation:
return Evoral::Parameter(MidiChannelPressureAutomation, channel);
case MidiPitchBenderAutomation:
return Evoral::Parameter(MidiPitchBenderAutomation, channel);
case MidiSystemExclusiveAutomation:
return Evoral::Parameter(MidiSystemExclusiveAutomation, channel);
default:
return Evoral::Parameter(NullAutomation);
}
}
inline bool
parameter_is_midi(AutomationType type)
{

View file

@ -56,6 +56,8 @@ class LIBARDOUR_API PluginManager : public boost::noncopyable {
void cancel_plugin_timeout();
void clear_vst_cache ();
void clear_vst_blacklist ();
void clear_au_cache ();
void clear_au_blacklist ();
const std::string get_default_windows_vst_path() const { return windows_vst_path; }
const std::string get_default_lxvst_path() const { return lxvst_path; }

View file

@ -55,6 +55,9 @@ public:
return _name;
}
/** @return Port human readable name */
std::string pretty_name (bool fallback_to_name = false) const;
int set_name (std::string const &);
/** @return flags */

View file

@ -119,6 +119,25 @@ class LIBARDOUR_API PortEngine {
*/
virtual std::string get_port_name (PortHandle) const = 0;
/** Return the port-property value and type for a given key.
* (eg query a human readable port name)
*
* The API follows jack_get_property():
*
* @param key The key of the property to retrieve
* @param value Set to the value of the property if found
* @param type The type of the property if set (
* Type of data, either a MIME type or URI.
* If type is empty, the data is assumed to be a UTF-8 encoded string.
*
* @return 0 on success, -1 if the @p subject has no @p key property.
*
* for available keys, see
* https://github.com/jackaudio/headers/blob/master/metadata.h
* https://github.com/drobilla/jackey/blob/master/jackey.h
*/
virtual int get_port_property (PortHandle, const std::string& key, std::string& value, std::string& type) const { return -1; }
/** Return a reference to a port with the fullname @param name. Return
* an "empty" PortHandle (analogous to a null pointer) if no such port exists.
*/
@ -336,7 +355,7 @@ class LIBARDOUR_API PortEngine {
*
* XXX to be removed after some more design cleanup.
*/
virtual pframes_t sample_time_at_cycle_start () = 0;
virtual framepos_t sample_time_at_cycle_start () = 0;
protected:
PortManager& manager;

View file

@ -79,6 +79,7 @@ class LIBARDOUR_API PortManager
void port_renamed (const std::string&, const std::string&);
std::string make_port_name_relative (const std::string& name) const;
std::string make_port_name_non_relative (const std::string& name) const;
std::string get_pretty_name_by_name (const std::string& portname) const;
bool port_is_mine (const std::string& fullname) const;
/* other Port management */

View file

@ -35,8 +35,8 @@ public:
~Quantize ();
Command* operator() (boost::shared_ptr<ARDOUR::MidiModel>,
Evoral::MusicalTime position,
std::vector<Evoral::Sequence<Evoral::MusicalTime>::Notes>&);
Evoral::Beats position,
std::vector<Evoral::Sequence<Evoral::Beats>::Notes>&);
std::string name() const { return std::string ("quantize"); }
private:

View file

@ -25,6 +25,13 @@
the value of the variable.
*****************************************************/
/*****************************************************
DO dump the config using cfgtool to system_config
after modifying this file.
./waf && build/cfgtool/cfgtool system_config
*****************************************************/
/* IO connection */
CONFIG_VARIABLE (bool, auto_connect_standard_busses, "auto-connect-standard-busses", true)
@ -50,7 +57,7 @@ CONFIG_VARIABLE (int32_t, inter_scene_gap_msecs, "inter-scene-gap-msecs", 1)
CONFIG_VARIABLE (int, mtc_qf_speed_tolerance, "mtc-qf-speed-tolerance", 5)
CONFIG_VARIABLE (bool, timecode_sync_frame_rate, "timecode-sync-frame-rate", true)
CONFIG_VARIABLE (bool, timecode_source_is_synced, "timecode-source-is-synced", true)
CONFIG_VARIABLE (bool, timecode_source_is_synced, "timecode-source-is-synced", false)
CONFIG_VARIABLE (bool, timecode_source_2997, "timecode-source-2997", false)
CONFIG_VARIABLE (SyncSource, sync_source, "sync-source", Engine)
CONFIG_VARIABLE (std::string, ltc_source_port, "ltc-source-port", "system:capture_1")
@ -67,7 +74,8 @@ CONFIG_VARIABLE (RemoteModel, remote_model, "remote-model", MixerOrdered)
/* disk operations */
CONFIG_VARIABLE (uint32_t, minimum_disk_io_bytes, "minimum-disk-io-bytes", 1024 * 256)
CONFIG_VARIABLE (uint32_t, minimum_disk_read_bytes, "minimum-disk-read-bytes", ARDOUR::Diskstream::default_disk_read_chunk_frames() * sizeof (ARDOUR::Sample))
CONFIG_VARIABLE (uint32_t, minimum_disk_write_bytes, "minimum-disk-write-bytes", ARDOUR::Diskstream::default_disk_write_chunk_frames() * sizeof (ARDOUR::Sample))
CONFIG_VARIABLE (float, midi_readahead, "midi-readahead", 1.0)
CONFIG_VARIABLE (float, audio_capture_buffer_seconds, "capture-buffer-seconds", 5.0)
CONFIG_VARIABLE (float, audio_playback_buffer_seconds, "playback-buffer-seconds", 5.0)
@ -90,7 +98,7 @@ CONFIG_VARIABLE (RegionSelectionAfterSplit, region_selection_after_split, "regio
/* monitoring, mute, solo etc */
CONFIG_VARIABLE (bool, mute_affects_pre_fader, "mute-affects-pre-fader", true)
CONFIG_VARIABLE (bool, mute_affects_pre_fader, "mute-affects-pre-fader", false)
CONFIG_VARIABLE (bool, mute_affects_post_fader, "mute-affects-post-fader", true)
CONFIG_VARIABLE (bool, mute_affects_control_outs, "mute-affects-control-outs", true)
CONFIG_VARIABLE (bool, mute_affects_main_outs, "mute-affects-main-outs", true)

View file

@ -1,19 +1,19 @@
/*
Copyright (C) 2000 Paul Davis
Copyright (C) 2000 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 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.
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.
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.
*/
@ -70,18 +70,18 @@ struct _AEffect;
typedef struct _AEffect AEffect;
namespace MIDI {
class Port;
class MachineControl;
class Parser;
class Port;
class MachineControl;
class Parser;
}
namespace PBD {
class Controllable;
class ControllableDescriptor;
class Controllable;
class ControllableDescriptor;
}
namespace Evoral {
class Curve;
class Curve;
}
namespace ARDOUR {
@ -160,7 +160,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
virtual ~Session ();
static int get_info_from_path (const std::string& xmlpath, float& sample_rate, SampleFormat& data_format);
static int get_info_from_path (const std::string& xmlpath, float& sample_rate, SampleFormat& data_format);
std::string path() const { return _path; }
std::string name() const { return _name; }
@ -193,12 +193,12 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
std::string peak_path (std::string) const;
std::string peak_path_from_audio_path (std::string) const;
bool audio_source_name_is_unique (const std::string& name, uint32_t chan);
bool audio_source_name_is_unique (const std::string& name);
std::string format_audio_source_name (const std::string& legalized_base, uint32_t nchan, uint32_t chan, bool destructive, bool take_required, uint32_t cnt, bool related_exists);
std::string new_audio_source_path_for_embedded (const std::string& existing_path);
std::string new_audio_source_path (const std::string&, uint32_t nchans, uint32_t chan, bool destructive, bool take_required);
std::string new_midi_source_path (const std::string&);
RouteList new_route_from_template (uint32_t how_many, const std::string& template_path, const std::string& name);
RouteList new_route_from_template (uint32_t how_many, const std::string& template_path, const std::string& name);
std::vector<std::string> get_paths_for_new_sources (bool allow_replacing, const std::string& import_file_path, uint32_t channels);
int bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,std::string)> callback);
@ -243,13 +243,13 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
bool operator() (boost::shared_ptr<Route>, boost::shared_ptr<Route> b);
};
void set_order_hint (uint32_t order_hint) {_order_hint = order_hint;};
void notify_remote_id_change ();
void sync_order_keys ();
void set_order_hint (int32_t order_hint) {_order_hint = order_hint;};
void notify_remote_id_change ();
void sync_order_keys ();
template<class T> void foreach_route (T *obj, void (T::*func)(Route&));
template<class T> void foreach_route (T *obj, void (T::*func)(boost::shared_ptr<Route>));
template<class T, class A> void foreach_route (T *obj, void (T::*func)(Route&, A), A arg);
template<class T> void foreach_route (T *obj, void (T::*func)(Route&), bool sort = true);
template<class T> void foreach_route (T *obj, void (T::*func)(boost::shared_ptr<Route>), bool sort = true);
template<class T, class A> void foreach_route (T *obj, void (T::*func)(Route&, A), A arg, bool sort = true);
static char session_name_is_legal (const std::string&);
bool io_name_is_legal (const std::string&);
@ -257,7 +257,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
boost::shared_ptr<Route> route_by_id (PBD::ID);
boost::shared_ptr<Route> route_by_remote_id (uint32_t id);
boost::shared_ptr<Track> track_by_diskstream_id (PBD::ID);
void routes_using_input_from (const std::string& str, RouteList& rl);
void routes_using_input_from (const std::string& str, RouteList& rl);
bool route_name_unique (std::string) const;
bool route_name_internal (std::string) const;
@ -301,7 +301,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
* - change in the play range (from the process thread)
* - start (from the process thread)
* - engine halted
*/
*/
PBD::Signal0<void> TransportStateChange;
PBD::Signal1<void,framepos_t> PositionChanged; /* sent after any non-sequential motion */
@ -343,8 +343,8 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
void goto_start ();
void use_rf_shuttle_speed ();
void allow_auto_play (bool yn);
void request_transport_speed (double speed, bool as_default = false);
void request_transport_speed_nonzero (double, bool as_default = false);
void request_transport_speed (double speed, bool as_default = false);
void request_transport_speed_nonzero (double, bool as_default = false);
void request_overwrite_buffer (Track *);
void adjust_playback_buffering();
void adjust_capture_buffering();
@ -434,7 +434,21 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
PBD::Signal1<void,std::string> StateSaved;
PBD::Signal0<void> StateReady;
PBD::Signal0<void> SaveSession;
/* emitted when session needs to be saved due to some internal
* event or condition (i.e. not in response to a user request).
*
* Only one object should
* connect to this signal and take responsibility.
*
* Argument is the snapshot name to use when saving.
*/
PBD::Signal1<void,std::string> SaveSessionRequested;
/* emitted during a session save to allow other entities to add state, via
* extra XML, to the session state
*/
PBD::Signal0<void> SessionSaveUnderway;
std::vector<std::string> possible_states() const;
static std::vector<std::string> possible_states (std::string path);
@ -460,20 +474,20 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
StateOfTheState state_of_the_state() const { return _state_of_the_state; }
class StateProtector {
public:
StateProtector (Session* s) : _session (s) {
g_atomic_int_inc (&s->_suspend_save);
}
~StateProtector () {
if (g_atomic_int_dec_and_test (&_session->_suspend_save)) {
while (_session->_save_queued) {
_session->_save_queued = false;
_session->save_state ("");
}
public:
StateProtector (Session* s) : _session (s) {
g_atomic_int_inc (&s->_suspend_save);
}
~StateProtector () {
if (g_atomic_int_dec_and_test (&_session->_suspend_save)) {
while (_session->_save_queued) {
_session->_save_queued = false;
_session->save_state ("");
}
}
private:
Session * _session;
}
private:
Session * _session;
};
void add_route_group (RouteGroup *);
@ -556,7 +570,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
void timecode_time_subframes (framepos_t when, Timecode::Time&);
void timecode_duration (framecnt_t, Timecode::Time&) const;
void timecode_duration_string (char *, size_t len, framecnt_t) const;
void timecode_duration_string (char *, size_t len, framecnt_t) const;
framecnt_t convert_to_frames (AnyTime const & position);
framecnt_t any_duration_to_frames (framepos_t position, AnyTime const & duration);
@ -565,13 +579,12 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
static PBD::Signal1<void, framepos_t> EndTimeChanged;
void request_sync_source (Slave*);
bool synced_to_engine() const { return config.get_external_sync() && Config->get_sync_source() == Engine; }
bool synced_to_engine() const { return _slave && config.get_external_sync() && Config->get_sync_source() == Engine; }
double transport_speed() const { return _transport_speed; }
bool transport_stopped() const { return _transport_speed == 0.0f; }
bool transport_rolling() const { return _transport_speed != 0.0f; }
void set_silent (bool yn);
bool silent () { return _silent; }
TempoMap& tempo_map() { return *_tempo_map; }
@ -610,10 +623,10 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
int remove_last_capture ();
/** handlers should return 0 for "everything OK", and any other value for
/** handlers should return 0 for "everything OK", and any other value for
* "cannot setup audioengine".
*/
static PBD::Signal1<int,uint32_t> AudioEngineSetupRequired;
static PBD::Signal1<int,uint32_t> AudioEngineSetupRequired;
/** handlers should return -1 for "stop cleanup",
0 for "yes, delete this playlist",
@ -627,7 +640,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
static PBD::Signal2<int, framecnt_t, framecnt_t> AskAboutSampleRateMismatch;
/** handlers should return !0 for use pending state, 0 for ignore it.
*/
*/
static PBD::Signal0<int> AskAboutPendingState;
boost::shared_ptr<AudioFileSource> create_audio_source_for_session (
@ -659,9 +672,9 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
/* flattening stuff */
boost::shared_ptr<Region> write_one_track (Track&, framepos_t start, framepos_t end,
bool overwrite, std::vector<boost::shared_ptr<Source> >&, InterThreadInfo& wot,
boost::shared_ptr<Processor> endpoint,
bool include_endpoint, bool for_export, bool for_freeze);
bool overwrite, std::vector<boost::shared_ptr<Source> >&, InterThreadInfo& wot,
boost::shared_ptr<Processor> endpoint,
bool include_endpoint, bool for_export, bool for_freeze);
int freeze_all (InterThreadInfo&);
/* session-wide solo/mute/rec-enable */
@ -680,7 +693,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
void set_record_enabled (boost::shared_ptr<RouteList>, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false);
void set_solo_isolated (boost::shared_ptr<RouteList>, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false);
void set_monitoring (boost::shared_ptr<RouteList>, MonitorChoice, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false);
void set_exclusive_input_active (boost::shared_ptr<RouteList> rt, bool onoff, bool flip_others=false);
void set_exclusive_input_active (boost::shared_ptr<RouteList> rt, bool onoff, bool flip_others=false);
PBD::Signal1<void,bool> SoloActive;
PBD::Signal0<void> SoloChanged;
@ -728,12 +741,11 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
/* I/O bundles */
void add_bundle (boost::shared_ptr<Bundle>);
void add_bundle (boost::shared_ptr<Bundle>, bool emit_signal = true);
void remove_bundle (boost::shared_ptr<Bundle>);
boost::shared_ptr<Bundle> bundle_by_name (std::string) const;
PBD::Signal1<void,boost::shared_ptr<Bundle> > BundleAdded;
PBD::Signal1<void,boost::shared_ptr<Bundle> > BundleRemoved;
PBD::Signal0<void> BundleAddedOrRemoved;
void midi_panic ();
@ -759,6 +771,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
void begin_reversible_command (const std::string& cmd_name);
void begin_reversible_command (GQuark);
void abort_reversible_command ();
void commit_reversible_command (Command* cmd = 0);
void add_command (Command *const cmd) {
@ -878,13 +891,13 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
};
SlaveState slave_state() const { return _slave_state; }
Slave* slave() const { return _slave; }
Slave* slave() const { return _slave; }
boost::shared_ptr<SessionPlaylists> playlists;
void send_mmc_locate (framepos_t);
void queue_full_time_code () { _send_timecode_update = true; }
void queue_song_position_pointer () { /* currently does nothing */ }
void queue_full_time_code () { _send_timecode_update = true; }
void queue_song_position_pointer () { /* currently does nothing */ }
bool step_editing() const { return (_step_editors > 0); }
@ -923,15 +936,15 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
/** Emitted when the session wants Ardour to quit */
static PBD::Signal0<void> Quit;
/** Emitted when Ardour is asked to load a session in an older session
/** Emitted when Ardour is asked to load a session in an older session
* format, and makes a backup copy.
*/
static PBD::Signal2<void,std::string,std::string> VersionMismatch;
static PBD::Signal2<void,std::string,std::string> VersionMismatch;
SceneChanger* scene_changer() const { return _scene_changer; }
boost::shared_ptr<Port> ltc_input_port() const;
boost::shared_ptr<Port> ltc_output_port() const;
boost::shared_ptr<Port> ltc_input_port() const;
boost::shared_ptr<Port> ltc_output_port() const;
boost::shared_ptr<IO> ltc_input_io() { return _ltc_input; }
boost::shared_ptr<IO> ltc_output_io() { return _ltc_output; }
@ -958,7 +971,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
friend class AudioEngine;
void set_block_size (pframes_t nframes);
void set_frame_rate (framecnt_t nframes);
void reconnect_existing_routes (bool withLock, bool reconnect_master = true, bool reconnect_inputs = true, bool reconnect_outputs = true);
void reconnect_existing_routes (bool withLock, bool reconnect_master = true, bool reconnect_inputs = true, bool reconnect_outputs = true);
protected:
friend class Route;
@ -1004,6 +1017,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
double _transport_speed;
double _default_transport_speed;
double _last_transport_speed;
double _signalled_varispeed;
double _target_transport_speed;
CubicInterpolation interpolation;
@ -1095,8 +1109,8 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
int silent_process_routes (pframes_t, bool& need_butler);
/** @return 1 if there is a pending declick fade-in,
-1 if there is a pending declick fade-out,
0 if there is no pending declick.
-1 if there is a pending declick fade-out,
0 if there is no pending declick.
*/
int get_transport_declick_required () {
if (transport_sub_state & PendingDeclickIn) {
@ -1171,17 +1185,17 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
static const PostTransportWork ProcessCannotProceedMask =
PostTransportWork (
PostTransportInputChange|
PostTransportSpeed|
PostTransportReverse|
PostTransportCurveRealloc|
PostTransportAudition|
PostTransportLocate|
PostTransportStop|
PostTransportClearSubstate);
PostTransportInputChange|
PostTransportSpeed|
PostTransportReverse|
PostTransportCurveRealloc|
PostTransportAudition|
PostTransportLocate|
PostTransportStop|
PostTransportClearSubstate);
gint _post_transport_work; /* accessed only atomic ops */
PostTransportWork post_transport_work() const { return (PostTransportWork) g_atomic_int_get (const_cast<gint*>(&_post_transport_work)); }
PostTransportWork post_transport_work() const { return (PostTransportWork) g_atomic_int_get (const_cast<gint*>(&_post_transport_work)); }
void set_post_transport_work (PostTransportWork ptw) { g_atomic_int_set (&_post_transport_work, (gint) ptw); }
void add_post_transport_work (PostTransportWork ptw);
@ -1195,15 +1209,20 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
void reset_rf_scale (framecnt_t frames_moved);
Locations* _locations;
void location_added (Location*);
void location_removed (Location*);
void locations_changed ();
void _locations_changed (const Locations::LocationList&);
void location_added (Location*);
void location_removed (Location*);
void locations_changed ();
void _locations_changed (const Locations::LocationList&);
void update_skips (Location*, bool consolidate);
Locations::LocationList consolidate_skips (Location*);
void sync_locations_to_skips (const Locations::LocationList&);
PBD::ScopedConnectionList skip_connections;
void update_skips (Location*, bool consolidate);
void update_marks (Location* loc);
void update_loop (Location* loc);
void consolidate_skips (Location*);
void sync_locations_to_skips ();
void _sync_locations_to_skips ();
PBD::ScopedConnectionList skip_update_connections;
bool _ignore_skips_updates;
PBD::ScopedConnectionList punch_connections;
void auto_punch_start_changed (Location *);
@ -1214,10 +1233,10 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
void auto_loop_changed (Location *);
void auto_loop_declick_range (Location *, framepos_t &, framepos_t &);
int ensure_engine (uint32_t desired_sample_rate);
int ensure_engine (uint32_t desired_sample_rate);
void pre_engine_init (std::string path);
int post_engine_init ();
int immediately_post_engine ();
int immediately_post_engine ();
void remove_empty_sounds ();
void setup_midi_control ();
@ -1352,7 +1371,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
void start_locate (framepos_t, bool with_roll, bool with_flush, bool with_loop=false, bool force=false);
void force_locate (framepos_t frame, bool with_roll = false);
void set_track_speed (Track *, double speed);
void set_transport_speed (double speed, framepos_t destination_frame, bool abort = false, bool clear_state = false, bool as_default = false);
void set_transport_speed (double speed, framepos_t destination_frame, bool abort = false, bool clear_state = false, bool as_default = false);
void stop_transport (bool abort = false, bool clear_state = false);
void start_transport ();
void realtime_stop (bool abort, bool clear_state);
@ -1365,13 +1384,14 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
void post_transport ();
void engine_halted ();
void xrun_recovery ();
void set_track_loop (bool);
/* These are synchronous and so can only be called from within the process
* cycle
*/
/* These are synchronous and so can only be called from within the process
* cycle
*/
int send_full_time_code (framepos_t, pframes_t nframes);
void send_song_position_pointer (framepos_t);
int send_full_time_code (framepos_t, pframes_t nframes);
void send_song_position_pointer (framepos_t);
TempoMap *_tempo_map;
void tempo_map_changed (const PBD::PropertyChange&);
@ -1390,8 +1410,8 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
SerializedRCUManager<RouteList> routes;
void add_routes (RouteList&, bool input_auto_connect, bool output_auto_connect, bool save);
void add_routes_inner (RouteList&, bool input_auto_connect, bool output_auto_connect);
bool _adding_routes_in_progress;
void add_routes_inner (RouteList&, bool input_auto_connect, bool output_auto_connect);
bool _adding_routes_in_progress;
uint32_t destructive_index;
boost::shared_ptr<Route> XMLRouteFactory (const XMLNode&, int);
@ -1545,7 +1565,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
*/
std::list<GQuark> _current_trans_quarks;
int backend_sync_callback (TransportState, framepos_t);
int backend_sync_callback (TransportState, framepos_t);
void process_rtop (SessionEvent*);
@ -1636,7 +1656,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
/* realtime "apply to set of routes" operations */
template<typename T> SessionEvent*
get_rt_event (boost::shared_ptr<RouteList> rl, T targ, SessionEvent::RTeventCallback after, bool group_override,
void (Session::*method) (boost::shared_ptr<RouteList>, T, bool)) {
void (Session::*method) (boost::shared_ptr<RouteList>, T, bool)) {
SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
ev->rt_slot = boost::bind (method, this, rl, targ, group_override);
ev->rt_return = after;
@ -1684,16 +1704,16 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
GraphEdges _current_route_graph;
uint32_t next_control_id () const;
uint32_t _order_hint;
int32_t _order_hint;
bool ignore_route_processor_changes;
MidiClockTicker* midi_clock;
boost::shared_ptr<IO> _ltc_input;
boost::shared_ptr<IO> _ltc_output;
boost::shared_ptr<IO> _ltc_input;
boost::shared_ptr<IO> _ltc_output;
void reconnect_ltc_input ();
void reconnect_ltc_output ();
void reconnect_ltc_input ();
void reconnect_ltc_output ();
/* Scene Changing */
SceneChanger* _scene_changer;

View file

@ -111,16 +111,7 @@ public:
boost::shared_ptr<Region> region;
SessionEvent (Type t, Action a, framepos_t when, framepos_t where, double spd, bool yn = false, bool yn2 = false, bool yn3 = false)
: type (t)
, action (a)
, action_frame (when)
, target_frame (where)
, speed (spd)
, yes_or_no (yn)
, second_yes_or_no (yn2)
, third_yes_or_no (yn3)
, event_loop (0) {}
SessionEvent (Type t, Action a, framepos_t when, framepos_t where, double spd, bool yn = false, bool yn2 = false, bool yn3 = false);
void set_ptr (void* p) {
ptr = p;
@ -146,6 +137,8 @@ public:
static void create_per_thread_pool (const std::string& n, uint32_t nitems);
static void init_event_pool ();
CrossThreadPool* event_pool() const { return own_pool; }
private:
static PerThreadPool* pool;
CrossThreadPool* own_pool;
@ -161,6 +154,7 @@ public:
virtual void queue_event (SessionEvent *ev) = 0;
void clear_events (SessionEvent::Type type);
void clear_events (SessionEvent::Type type, boost::function<void (void)> after);
protected:
RingBuffer<SessionEvent*> pending_events;

View file

@ -52,6 +52,7 @@ class LIBARDOUR_API SessionMetadata : public PBD::StatefulDestructible
uint32_t year () const;
std::string grouping () const;
std::string barcode () const;
std::string title () const;
std::string subtitle () const;
@ -93,6 +94,7 @@ class LIBARDOUR_API SessionMetadata : public PBD::StatefulDestructible
void set_year (uint32_t);
void set_grouping (const std::string &);
void set_barcode (const std::string &);
void set_title (const std::string &);
void set_subtitle (const std::string &);

View file

@ -30,27 +30,29 @@
namespace ARDOUR {
template<class T> void
Session::foreach_route (T *obj, void (T::*func)(Route&))
Session::foreach_route (T *obj, void (T::*func)(Route&), bool sort)
{
boost::shared_ptr<RouteList> r = routes.reader();
RouteList public_order (*r);
RoutePublicOrderSorter cmp;
public_order.sort (cmp);
if (sort) {
public_order.sort (RoutePublicOrderSorter());
}
for (RouteList::iterator i = public_order.begin(); i != public_order.end(); i++) {
(obj->*func) (**i);
}
}
template<class T> void
Session::foreach_route (T *obj, void (T::*func)(boost::shared_ptr<Route>))
Session::foreach_route (T *obj, void (T::*func)(boost::shared_ptr<Route>), bool sort)
{
boost::shared_ptr<RouteList> r = routes.reader();
RouteList public_order (*r);
RoutePublicOrderSorter cmp;
public_order.sort (cmp);
if (sort) {
public_order.sort (RoutePublicOrderSorter());
}
for (RouteList::iterator i = public_order.begin(); i != public_order.end(); i++) {
(obj->*func) (*i);
@ -58,13 +60,14 @@ Session::foreach_route (T *obj, void (T::*func)(boost::shared_ptr<Route>))
}
template<class T, class A> void
Session::foreach_route (T *obj, void (T::*func)(Route&, A), A arg1)
Session::foreach_route (T *obj, void (T::*func)(Route&, A), A arg1, bool sort)
{
boost::shared_ptr<RouteList> r = routes.reader();
RouteList public_order (*r);
RoutePublicOrderSorter cmp;
public_order.sort (cmp);
if (sort) {
public_order.sort (RoutePublicOrderSorter());
}
for (RouteList::iterator i = public_order.begin(); i != public_order.end(); i++) {
(obj->*func) (**i, arg1);

View file

@ -189,7 +189,7 @@ class LIBARDOUR_API ISlaveSessionProxy {
virtual framepos_t audible_frame () const { return 0; }
virtual framepos_t transport_frame () const { return 0; }
virtual pframes_t frames_since_cycle_start () const { return 0; }
virtual pframes_t sample_time_at_cycle_start() const { return 0; }
virtual framepos_t sample_time_at_cycle_start() const { return 0; }
virtual framepos_t frame_time () const { return 0; }
virtual void request_locate (framepos_t /*frame*/, bool with_roll = false) {
@ -212,7 +212,7 @@ class LIBARDOUR_API SlaveSessionProxy : public ISlaveSessionProxy {
framepos_t audible_frame () const;
framepos_t transport_frame () const;
pframes_t frames_since_cycle_start () const;
pframes_t sample_time_at_cycle_start() const;
framepos_t sample_time_at_cycle_start() const;
framepos_t frame_time () const;
void request_locate (framepos_t frame, bool with_roll = false);
@ -388,6 +388,7 @@ public:
int ltc_detect_fps_cnt;
int ltc_detect_fps_max;
bool printed_timecode_warning;
bool sync_lock_broken;
Timecode::TimecodeFormat ltc_timecode;
Timecode::TimecodeFormat a3e_timecode;

View file

@ -51,14 +51,14 @@ public:
return safe_midi_file_extension(path);
}
void append_event_beats (const Lock& lock, const Evoral::Event<Evoral::MusicalTime>& ev);
void append_event_beats (const Lock& lock, const Evoral::Event<Evoral::Beats>& ev);
void append_event_frames (const Lock& lock, const Evoral::Event<framepos_t>& ev, framepos_t source_start);
void mark_streaming_midi_write_started (const Lock& lock, NoteMode mode);
void mark_streaming_write_completed (const Lock& lock);
void mark_midi_streaming_write_completed (const Lock& lock,
Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption,
Evoral::MusicalTime when = Evoral::MusicalTime());
Evoral::Sequence<Evoral::Beats>::StuckNoteOption,
Evoral::Beats when = Evoral::Beats());
XMLNode& get_state ();
int set_state (const XMLNode&, int version);
@ -77,7 +77,7 @@ public:
private:
bool _open;
Evoral::MusicalTime _last_ev_time_beats;
Evoral::Beats _last_ev_time_beats;
framepos_t _last_ev_time_frames;
/** end time (start + duration) of last call to read_unlocked */
mutable framepos_t _smf_last_read_end;
@ -93,7 +93,8 @@ public:
framepos_t position,
framepos_t start,
framecnt_t cnt,
MidiStateTracker* tracker) const;
MidiStateTracker* tracker,
MidiChannelFilter* filter) const;
framecnt_t write_unlocked (const Lock& lock,
MidiRingBuffer<framepos_t>& src,

View file

@ -23,6 +23,8 @@
#include <string>
#include <stdint.h>
#include "ardour/types.h"
// Use this define when initializing arrarys for use in sndfile_*_format()
#define SNDFILE_STR_LENGTH 32

View file

@ -276,9 +276,9 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
*/
framepos_t framepos_plus_bbt (framepos_t pos, Timecode::BBT_Time b) const;
framepos_t framepos_plus_beats (framepos_t, Evoral::MusicalTime) const;
framepos_t framepos_minus_beats (framepos_t, Evoral::MusicalTime) const;
Evoral::MusicalTime framewalk_to_beats (framepos_t pos, framecnt_t distance) const;
framepos_t framepos_plus_beats (framepos_t, Evoral::Beats) const;
framepos_t framepos_minus_beats (framepos_t, Evoral::Beats) const;
Evoral::Beats framewalk_to_beats (framepos_t pos, framecnt_t distance) const;
static const Tempo& default_tempo() { return _default_tempo; }
static const Meter& default_meter() { return _default_meter; }
@ -364,6 +364,13 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
TempoSection& first_tempo();
void do_insert (MetricSection* section);
void add_tempo_locked (const Tempo&, Timecode::BBT_Time where, bool recompute);
void add_meter_locked (const Meter&, Timecode::BBT_Time where, bool recompute);
bool remove_tempo_locked (const TempoSection&);
bool remove_meter_locked (const MeterSection&);
};
}; /* namespace ARDOUR */

View file

@ -50,9 +50,9 @@ namespace ARDOUR {
*/
class LIBARDOUR_API Transform : public MidiOperator {
public:
typedef Evoral::Sequence<Evoral::MusicalTime>::NotePtr NotePtr;
typedef Evoral::Sequence<Evoral::MusicalTime>::Notes Notes;
typedef ARDOUR::MidiModel::NoteDiffCommand::Property Property;
typedef Evoral::Sequence<Evoral::Beats>::NotePtr NotePtr;
typedef Evoral::Sequence<Evoral::Beats>::Notes Notes;
typedef ARDOUR::MidiModel::NoteDiffCommand::Property Property;
/** Context while iterating over notes during transformation. */
struct Context {
@ -106,7 +106,8 @@ public:
ADD, ///< Add top two values
SUB, ///< Subtract top from second-top
MULT, ///< Multiply top two values
DIV ///< Divide second-top by top
DIV, ///< Divide second-top by top
MOD ///< Modulus (division remainder)
};
Operation(Operator o, const Value& a=Value()) : op(o), arg(a) {}
@ -131,7 +132,7 @@ public:
Transform(const Program& prog);
Command* operator()(boost::shared_ptr<ARDOUR::MidiModel> model,
Evoral::MusicalTime position,
Evoral::Beats position,
std::vector<Notes>& seqs);
std::string name() const { return std::string ("transform"); }

View file

@ -456,6 +456,8 @@ namespace ARDOUR {
FormatInt16
};
int format_data_width (ARDOUR::SampleFormat);
enum CDMarkerFormat {
CDMarkerNone,
CDMarkerCUE,

View file

@ -57,7 +57,7 @@ public:
explicit Variant(int32_t value) : _type(INT) { _int = value; }
explicit Variant(int64_t value) : _type(LONG) { _long = value; }
explicit Variant(const Evoral::MusicalTime& beats)
explicit Variant(const Evoral::Beats& beats)
: _type(BEATS)
, _beats(beats)
{}
@ -94,7 +94,7 @@ public:
std::min(value, (double)INT64_MAX)));
break;
case BEATS:
_beats = Evoral::MusicalTime(value);
_beats = Evoral::Beats(value);
break;
default:
_type = NOTHING;
@ -158,19 +158,19 @@ public:
return false;
}
bool operator==(const Evoral::MusicalTime& v) const {
bool operator==(const Evoral::Beats& v) const {
return _type == BEATS && _beats == v;
}
bool operator!() const { return _type == NOTHING; }
Variant& operator=(Evoral::MusicalTime v) {
Variant& operator=(Evoral::Beats v) {
_type = BEATS;
_beats = v;
return *this;
}
const Evoral::MusicalTime& get_beats() const {
const Evoral::Beats& get_beats() const {
ensure_type(BEATS); return _beats;
}
@ -202,9 +202,9 @@ private:
}
}
Type _type; ///< Type tag
std::string _string; ///< PATH, STRING, URI
Evoral::MusicalTime _beats; ///< BEATS
Type _type; ///< Type tag
std::string _string; ///< PATH, STRING, URI
Evoral::Beats _beats; ///< BEATS
// Union of all primitive numeric types
union {

View file

@ -128,9 +128,7 @@ AudioDiskstream::~AudioDiskstream ()
void
AudioDiskstream::allocate_working_buffers()
{
assert(disk_io_frames() > 0);
_working_buffers_size = disk_io_frames();
_working_buffers_size = max (disk_write_chunk_frames, disk_read_chunk_frames);
_mixdown_buffer = new Sample[_working_buffers_size];
_gain_buffer = new gain_t[_working_buffers_size];
}
@ -227,7 +225,7 @@ AudioDiskstream::get_input_sources ()
connections.clear ();
if (_io->nth (n)->get_connections (connections) == 0) {
if ((_io->nth (n).get()) && (_io->nth (n)->get_connections (connections) == 0)) {
if (!(*chan)->source.name.empty()) {
// _source->disable_metering ();
}
@ -786,10 +784,10 @@ AudioDiskstream::commit (framecnt_t playback_distance)
}
} else {
if (_io && _io->active()) {
need_butler = ((framecnt_t) c->front()->playback_buf->write_space() >= disk_io_chunk_frames)
|| ((framecnt_t) c->front()->capture_buf->read_space() >= disk_io_chunk_frames);
need_butler = ((framecnt_t) c->front()->playback_buf->write_space() >= disk_read_chunk_frames)
|| ((framecnt_t) c->front()->capture_buf->read_space() >= disk_write_chunk_frames);
} else {
need_butler = ((framecnt_t) c->front()->capture_buf->read_space() >= disk_io_chunk_frames);
need_butler = ((framecnt_t) c->front()->capture_buf->read_space() >= disk_write_chunk_frames);
}
}
@ -997,6 +995,7 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
if (loc && start >= loop_end) {
start = loop_start + ((start - loop_start) % loop_length);
}
}
if (reversed) {
@ -1056,8 +1055,8 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
int
AudioDiskstream::do_refill_with_alloc ()
{
Sample* mix_buf = new Sample[disk_io_chunk_frames];
float* gain_buf = new float[disk_io_chunk_frames];
Sample* mix_buf = new Sample[disk_read_chunk_frames];
float* gain_buf = new float[disk_read_chunk_frames];
int ret = _do_refill(mix_buf, gain_buf);
@ -1108,22 +1107,22 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
for us to be called again, ASAP.
*/
if (total_space >= (_slaved ? 3 : 2) * disk_io_chunk_frames) {
if (total_space >= (_slaved ? 3 : 2) * disk_read_chunk_frames) {
ret = 1;
}
/* if we're running close to normal speed and there isn't enough
space to do disk_io_chunk_frames of I/O, then don't bother.
space to do disk_read_chunk_frames of I/O, then don't bother.
at higher speeds, just do it because the sync between butler
and audio thread may not be good enough.
Note: it is a design assumption that disk_io_chunk_frames is smaller
Note: it is a design assumption that disk_read_chunk_frames is smaller
than the playback buffer size, so this check should never trip when
the playback buffer is empty.
*/
if ((total_space < disk_io_chunk_frames) && fabs (_actual_speed) < 2.0f) {
if ((total_space < disk_read_chunk_frames) && fabs (_actual_speed) < 2.0f) {
return 0;
}
@ -1136,9 +1135,9 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
return 0;
}
/* never do more than disk_io_chunk_frames worth of disk input per call (limit doesn't apply for memset) */
/* never do more than disk_read_chunk_frames worth of disk input per call (limit doesn't apply for memset) */
total_space = min (disk_io_chunk_frames, total_space);
total_space = min (disk_read_chunk_frames, total_space);
if (reversed) {
@ -1215,14 +1214,14 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
chan->playback_buf->get_write_vector (&vector);
if ((framecnt_t) vector.len[0] > disk_io_chunk_frames) {
if ((framecnt_t) vector.len[0] > disk_read_chunk_frames) {
/* we're not going to fill the first chunk, so certainly do not bother with the
other part. it won't be connected with the part we do fill, as in:
.... => writable space
++++ => readable space
^^^^ => 1 x disk_io_chunk_frames that would be filled
^^^^ => 1 x disk_read_chunk_frames that would be filled
|......|+++++++++++++|...............................|
buf1 buf0
@ -1247,7 +1246,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
len2 = vector.len[1];
to_read = min (ts, len1);
to_read = min (to_read, disk_io_chunk_frames);
to_read = min (to_read, disk_read_chunk_frames);
assert (to_read >= 0);
@ -1266,7 +1265,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
if (to_read) {
/* we read all of vector.len[0], but it wasn't an entire disk_io_chunk_frames of data,
/* we read all of vector.len[0], but it wasn't an entire disk_read_chunk_frames of data,
so read some or all of vector.len[1] as well.
*/
@ -1294,12 +1293,12 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
/** Flush pending data to disk.
*
* Important note: this function will write *AT MOST* disk_io_chunk_frames
* Important note: this function will write *AT MOST* disk_write_chunk_frames
* of data to disk. it will never write more than that. If it writes that
* much and there is more than that waiting to be written, it will return 1,
* otherwise 0 on success or -1 on failure.
*
* If there is less than disk_io_chunk_frames to be written, no data will be
* If there is less than disk_write_chunk_frames to be written, no data will be
* written at all unless @a force_flush is true.
*/
int
@ -1323,7 +1322,7 @@ AudioDiskstream::do_flush (RunContext /*context*/, bool force_flush)
total = vector.len[0] + vector.len[1];
if (total == 0 || (total < disk_io_chunk_frames && !force_flush && was_recording)) {
if (total == 0 || (total < disk_write_chunk_frames && !force_flush && was_recording)) {
goto out;
}
@ -1338,11 +1337,11 @@ AudioDiskstream::do_flush (RunContext /*context*/, bool force_flush)
let the caller know too.
*/
if (total >= 2 * disk_io_chunk_frames || ((force_flush || !was_recording) && total > disk_io_chunk_frames)) {
if (total >= 2 * disk_write_chunk_frames || ((force_flush || !was_recording) && total > disk_write_chunk_frames)) {
ret = 1;
}
to_write = min (disk_io_chunk_frames, (framecnt_t) vector.len[0]);
to_write = min (disk_write_chunk_frames, (framecnt_t) vector.len[0]);
// check the transition buffer when recording destructive
// important that we get this after the capture buf
@ -1402,14 +1401,14 @@ AudioDiskstream::do_flush (RunContext /*context*/, bool force_flush)
(*chan)->capture_buf->increment_read_ptr (to_write);
(*chan)->curr_capture_cnt += to_write;
if ((to_write == vector.len[0]) && (total > to_write) && (to_write < disk_io_chunk_frames) && !destructive()) {
if ((to_write == vector.len[0]) && (total > to_write) && (to_write < disk_write_chunk_frames) && !destructive()) {
/* we wrote all of vector.len[0] but it wasn't an entire
disk_io_chunk_frames of data, so arrange for some part
disk_write_chunk_frames of data, so arrange for some part
of vector.len[1] to be flushed to disk as well.
*/
to_write = min ((framecnt_t)(disk_io_chunk_frames - to_write), (framecnt_t) vector.len[1]);
to_write = min ((framecnt_t)(disk_write_chunk_frames - to_write), (framecnt_t) vector.len[1]);
DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 additional write of %2\n", name(), to_write));
@ -1805,7 +1804,7 @@ AudioDiskstream::get_state ()
{
XMLNode& node (Diskstream::get_state());
char buf[64] = "";
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
boost::shared_ptr<ChannelList> c = channels.reader();
snprintf (buf, sizeof(buf), "%u", (unsigned int) c->size());
@ -1847,7 +1846,7 @@ AudioDiskstream::set_state (const XMLNode& node, int version)
XMLNodeIterator niter;
uint32_t nchans = 1;
XMLNode* capture_pending_node = 0;
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
/* prevent write sources from being created */
@ -2446,6 +2445,24 @@ AudioDiskstream::ChannelInfo::resize_capture (framecnt_t capture_bufsize)
AudioDiskstream::ChannelInfo::~ChannelInfo ()
{
if (write_source) {
if (write_source->removable()) {
/* this is a "stub" write source which exists in the
Session source list, but is removable. We must emit
a drop references call because it should not
continue to exist. If we do not do this, then the
Session retains a reference to it, it is not
deleted, and later attempts to create a new source
file will use wierd naming because it already
exists.
XXX longer term TO-DO: do not add to session source
list until we write to the source.
*/
write_source->drop_references ();
}
}
write_source.reset ();
delete [] speed_buffer;

View file

@ -244,7 +244,7 @@ AudioTrack::set_state_part_two ()
{
XMLNode* fnode;
XMLProperty* prop;
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
/* This is called after all session state has been restored but before
have been made ports and connections are established.

View file

@ -74,6 +74,75 @@ static string preset_suffix = ".aupreset";
static bool preset_search_path_initialized = false;
FILE * AUPluginInfo::_crashlog_fd = NULL;
static void au_blacklist (std::string id)
{
string fn = Glib::build_filename (ARDOUR::user_cache_directory(), "au_blacklist.txt");
FILE * blacklist_fd = NULL;
if (! (blacklist_fd = fopen(fn.c_str(), "a"))) {
PBD::error << "Cannot append to AU blacklist for '"<< id <<"'\n";
return;
}
assert(id.find("\n") == string::npos);
fprintf(blacklist_fd, "%s\n", id.c_str());
::fclose(blacklist_fd);
}
static void au_unblacklist (std::string id)
{
string fn = Glib::build_filename (ARDOUR::user_cache_directory(), "au_blacklist.txt");
if (!Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
PBD::warning << "Expected Blacklist file does not exist.\n";
return;
}
std::string bl;
std::ifstream ifs(fn.c_str());
bl.assign ((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
::g_unlink(fn.c_str());
assert(id.find("\n") == string::npos);
id += "\n"; // add separator
const size_t rpl = bl.find(id);
if (rpl != string::npos) {
bl.replace(rpl, id.size(), "");
}
if (bl.empty()) {
return;
}
FILE * blacklist_fd = NULL;
if (! (blacklist_fd = fopen(fn.c_str(), "w"))) {
PBD::error << "Cannot open AU blacklist.\n";
return;
}
fprintf(blacklist_fd, "%s", bl.c_str());
::fclose(blacklist_fd);
}
static bool is_blacklisted (std::string id)
{
string fn = Glib::build_filename (ARDOUR::user_cache_directory(), "au_blacklist.txt");
if (!Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
return false;
}
std::string bl;
std::ifstream ifs(fn.c_str());
bl.assign ((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
assert(id.find("\n") == string::npos);
id += "\n"; // add separator
const size_t rpl = bl.find(id);
if (rpl != string::npos) {
return true;
}
return false;
}
static OSStatus
_render_callback(void *userData,
AudioUnitRenderActionFlags *ioActionFlags,
@ -360,6 +429,7 @@ AUPlugin::AUPlugin (AudioEngine& engine, Session& session, boost::shared_ptr<CAC
p += preset_search_path;
preset_search_path = p;
preset_search_path_initialized = true;
DEBUG_TRACE (DEBUG::AudioUnits, string_compose("AU Preset Path: %1\n", preset_search_path));
}
init ();
@ -434,6 +504,7 @@ AUPlugin::discover_factory_presets ()
string name = CFStringRefToStdString (preset->presetName);
factory_preset_map[name] = preset->presetNumber;
DEBUG_TRACE (DEBUG::AudioUnits, string_compose("AU Factory Preset: %1 > %2\n", name, preset->presetNumber));
}
CFRelease (presets);
@ -443,6 +514,7 @@ void
AUPlugin::init ()
{
OSErr err;
CFStringRef itemName;
/* these keep track of *configured* channel set up,
not potential set ups.
@ -450,6 +522,20 @@ AUPlugin::init ()
input_channels = -1;
output_channels = -1;
{
CAComponentDescription temp;
GetComponentInfo (comp.get()->Comp(), &temp, NULL, NULL, NULL);
CFStringRef compTypeString = UTCreateStringForOSType(temp.componentType);
CFStringRef compSubTypeString = UTCreateStringForOSType(temp.componentSubType);
CFStringRef compManufacturerString = UTCreateStringForOSType(temp.componentManufacturer);
itemName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ - %@ - %@"),
compTypeString, compManufacturerString, compSubTypeString);
if (compTypeString != NULL) CFRelease(compTypeString);
if (compSubTypeString != NULL) CFRelease(compSubTypeString);
if (compManufacturerString != NULL) CFRelease(compManufacturerString);
}
au_blacklist(CFStringRefToStdString(itemName));
try {
DEBUG_TRACE (DEBUG::AudioUnits, "opening AudioUnit\n");
@ -515,6 +601,9 @@ AUPlugin::init ()
discover_factory_presets ();
// Plugin::setup_controls ();
au_unblacklist(CFStringRefToStdString(itemName));
if (itemName != NULL) CFRelease(itemName);
}
void
@ -532,7 +621,7 @@ AUPlugin::discover_parameters ()
for (uint32_t i = 0; i < sizeof (scopes) / sizeof (scopes[0]); ++i) {
AUParamInfo param_info (unit->AU(), false, false, scopes[i]);
AUParamInfo param_info (unit->AU(), false, /* include read only */ true, scopes[i]);
for (uint32_t i = 0; i < param_info.NumParams(); ++i) {
@ -612,7 +701,7 @@ AUPlugin::discover_parameters ()
d.toggled = (info.unit == kAudioUnitParameterUnit_Boolean) ||
(d.integer_step && ((d.upper - d.lower) == 1.0));
d.sr_dependent = (info.unit == kAudioUnitParameterUnit_SampleFrames);
d.automatable = !d.toggled &&
d.automatable = /* !d.toggled && -- ardour can automate toggles, can AU ? */
!(info.flags & kAudioUnitParameterFlag_NonRealTime) &&
(info.flags & kAudioUnitParameterFlag_IsWritable);
@ -977,11 +1066,11 @@ AUPlugin::input_streams() const
{
ChanCount c;
c.set (DataType::AUDIO, 1);
c.set (DataType::MIDI, 0);
if (input_channels < 0) {
warning << string_compose (_("AUPlugin: %1 input_streams() called without any format set!"), name()) << endmsg;
// force PluginIoReConfigure -- see also commit msg e38eb06
c.set (DataType::AUDIO, 0);
c.set (DataType::MIDI, 0);
} else {
c.set (DataType::AUDIO, input_channels);
c.set (DataType::MIDI, _has_midi_input ? 1 : 0);
@ -996,11 +1085,10 @@ AUPlugin::output_streams() const
{
ChanCount c;
c.set (DataType::AUDIO, 1);
c.set (DataType::MIDI, 0);
if (output_channels < 0) {
warning << string_compose (_("AUPlugin: %1 output_streams() called without any format set!"), name()) << endmsg;
// force PluginIoReConfigure - see also commit msg e38eb06
c.set (DataType::AUDIO, 0);
c.set (DataType::MIDI, 0);
} else {
c.set (DataType::AUDIO, output_channels);
c.set (DataType::MIDI, _has_midi_output ? 1 : 0);
@ -1037,7 +1125,11 @@ AUPlugin::can_support_io_configuration (const ChanCount& in, ChanCount& out)
//configurations in most cases. so first lets see
//if there's a configuration that keeps out==in
audio_out = audio_in;
if (in.n_midi() > 0 && audio_in == 0) {
audio_out = 2; // prefer stereo version if available.
} else {
audio_out = audio_in;
}
for (vector<pair<int,int> >::iterator i = io_configs.begin(); i != io_configs.end(); ++i) {
@ -1663,27 +1755,42 @@ AUPlugin::parameter_is_audio (uint32_t) const
}
bool
AUPlugin::parameter_is_control (uint32_t) const
{
return true;
}
bool
AUPlugin::parameter_is_input (uint32_t) const
AUPlugin::parameter_is_control (uint32_t param) const
{
assert(param < descriptors.size());
if (descriptors[param].automatable) {
/* corrently ardour expects all controls to be automatable
* IOW ardour GUI elements mandate an Evoral::Parameter
* for all input+control ports.
*/
return true;
}
return false;
}
bool
AUPlugin::parameter_is_output (uint32_t) const
AUPlugin::parameter_is_input (uint32_t param) const
{
return false;
/* AU params that are both readable and writeable,
* are listed in kAudioUnitScope_Global
*/
return (descriptors[param].scope == kAudioUnitScope_Input || descriptors[param].scope == kAudioUnitScope_Global);
}
bool
AUPlugin::parameter_is_output (uint32_t param) const
{
assert(param < descriptors.size());
// TODO check if ardour properly handles ports
// that report is_input + is_output == true
// -> add || descriptors[param].scope == kAudioUnitScope_Global
return (descriptors[param].scope == kAudioUnitScope_Output);
}
void
AUPlugin::add_state (XMLNode* root) const
{
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
CFDataRef xmlData;
CFPropertyListRef propertyList;
@ -1722,7 +1829,7 @@ AUPlugin::set_state(const XMLNode& node, int version)
{
int ret = -1;
CFPropertyListRef propertyList;
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
if (node.name() != state_node_name()) {
error << _("Bad node sent to AUPlugin::set_state") << endmsg;
@ -1879,6 +1986,10 @@ AUPlugin::do_save_preset (string preset_name)
CFRelease(propertyList);
user_preset_map[preset_name] = user_preset_path;;
DEBUG_TRACE (DEBUG::AudioUnits, string_compose("AU Saving Preset to %1\n", user_preset_path));
return string ("file:///") + user_preset_path;
}
@ -2067,6 +2178,7 @@ AUPlugin::find_presets ()
find_files_matching_filter (preset_files, preset_search_path, au_preset_filter, this, true, true, true);
if (preset_files.empty()) {
DEBUG_TRACE (DEBUG::AudioUnits, "AU No Preset Files found for given plugin.\n");
return;
}
@ -2087,6 +2199,9 @@ AUPlugin::find_presets ()
if (check_and_get_preset_name (get_comp()->Comp(), path, preset_name)) {
user_preset_map[preset_name] = path;
DEBUG_TRACE (DEBUG::AudioUnits, string_compose("AU Preset File: %1 > %2\n", preset_name, path));
} else {
DEBUG_TRACE (DEBUG::AudioUnits, string_compose("AU INVALID Preset: %1 > %2\n", preset_name, path));
}
}
@ -2095,6 +2210,7 @@ AUPlugin::find_presets ()
for (UserPresetMap::iterator i = user_preset_map.begin(); i != user_preset_map.end(); ++i) {
_presets.insert (make_pair (i->second, Plugin::PresetRecord (i->second, i->first)));
DEBUG_TRACE (DEBUG::AudioUnits, string_compose("AU Adding User Preset: %1 > %2\n", i->first, i->second));
}
/* add factory presets */
@ -2103,6 +2219,7 @@ AUPlugin::find_presets ()
/* XXX: dubious */
string const uri = string_compose ("%1", _presets.size ());
_presets.insert (make_pair (uri, Plugin::PresetRecord (uri, i->first, i->second)));
DEBUG_TRACE (DEBUG::AudioUnits, string_compose("AU Adding Factory Preset: %1 > %2\n", i->first, i->second));
}
}
@ -2294,12 +2411,14 @@ AUPluginInfo::discover_by_description (PluginInfoList& plugs, CAComponentDescrip
while (comp != NULL) {
CAComponentDescription temp;
GetComponentInfo (comp, &temp, NULL, NULL, NULL);
CFStringRef itemName = NULL;
{
if (itemName != NULL) CFRelease(itemName);
CFStringRef compTypeString = UTCreateStringForOSType(temp.componentType);
CFStringRef compSubTypeString = UTCreateStringForOSType(temp.componentSubType);
CFStringRef compManufacturerString = UTCreateStringForOSType(temp.componentManufacturer);
CFStringRef itemName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ - %@ - %@"),
itemName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ - %@ - %@"),
compTypeString, compManufacturerString, compSubTypeString);
au_crashlog(string_compose("Scanning ID: %1", CFStringRefToStdString(itemName)));
if (compTypeString != NULL)
@ -2310,6 +2429,12 @@ AUPluginInfo::discover_by_description (PluginInfoList& plugs, CAComponentDescrip
CFRelease(compManufacturerString);
}
if (is_blacklisted(CFStringRefToStdString(itemName))) {
info << string_compose (_("Skipped blacklisted AU plugin %1 "), CFStringRefToStdString(itemName)) << endmsg;
comp = FindNextComponent (comp, &desc);
continue;
}
AUPluginInfoPtr info (new AUPluginInfo
(boost::shared_ptr<CAComponentDescription> (new CAComponentDescription(temp))));
@ -2326,6 +2451,7 @@ AUPluginInfo::discover_by_description (PluginInfoList& plugs, CAComponentDescrip
case kAudioUnitType_Panner:
case kAudioUnitType_OfflineEffect:
case kAudioUnitType_FormatConverter:
comp = FindNextComponent (comp, &desc);
continue;
case kAudioUnitType_Output:
@ -2351,6 +2477,7 @@ AUPluginInfo::discover_by_description (PluginInfoList& plugs, CAComponentDescrip
break;
}
au_blacklist(CFStringRefToStdString(itemName));
AUPluginInfo::get_names (temp, info->name, info->creator);
ARDOUR::PluginScanMessage(_("AU"), info->name, false);
au_crashlog(string_compose("Plugin: %1", info->name));
@ -2406,8 +2533,10 @@ AUPluginInfo::discover_by_description (PluginInfoList& plugs, CAComponentDescrip
error << string_compose (_("Cannot get I/O configuration info for AU %1"), info->name) << endmsg;
}
au_unblacklist(CFStringRefToStdString(itemName));
au_crashlog("Success.");
comp = FindNextComponent (comp, &desc);
if (itemName != NULL) CFRelease(itemName); itemName = NULL;
}
au_crashlog(string_compose("End AU discovery for Type: %1", (int)desc.componentType));
}

View file

@ -64,7 +64,7 @@ AudioAnalyser::initialize_plugin (AnalysisPluginKey key, float sr)
PluginLoader* loader (PluginLoader::getInstance());
plugin = loader->loadPlugin (key, sr, PluginLoader::ADAPT_ALL);
plugin = loader->loadPlugin (key, sr, PluginLoader::ADAPT_ALL_SAFE);
if (!plugin) {
error << string_compose (_("VAMP Plugin \"%1\" could not be loaded"), key) << endmsg;
@ -75,8 +75,8 @@ AudioAnalyser::initialize_plugin (AnalysisPluginKey key, float sr)
something that makes for efficient disk i/o
*/
bufsize = 65536;
stepsize = bufsize;
bufsize = 1024;
stepsize = 512;
if (plugin->getMinChannelCount() > 1) {
delete plugin;

View file

@ -23,6 +23,7 @@
#include <exception>
#include <stdexcept>
#include <sstream>
#include <cmath>
#include <glibmm/timer.h>
#include <glibmm/pattern.h>
@ -63,6 +64,10 @@ using namespace PBD;
gint AudioEngine::m_meter_exit;
AudioEngine* AudioEngine::_instance = 0;
#ifdef SILENCE_AFTER
#define SILENCE_AFTER_SECONDS 600
#endif
AudioEngine::AudioEngine ()
: session_remove_pending (false)
, session_removal_countdown (-1)
@ -89,9 +94,14 @@ AudioEngine::AudioEngine ()
, _hw_devicelist_update_thread(0)
, _hw_devicelist_update_count(0)
, _stop_hw_devicelist_processing(0)
#ifdef SILENCE_AFTER_SECONDS
, _silence_countdown (0)
, _silence_hit_cnt (0)
#endif
{
g_atomic_int_set (&m_meter_exit, 0);
start_hw_event_processing();
reset_silence_countdown ();
start_hw_event_processing();
discover_backends ();
}
@ -148,6 +158,10 @@ AudioEngine::sample_rate_change (pframes_t nframes)
SampleRateChanged (nframes); /* EMIT SIGNAL */
#ifdef SILENCE_AFTER_SECONDS
_silence_countdown = nframes * SILENCE_AFTER_SECONDS;
#endif
return 0;
}
@ -333,10 +347,12 @@ AudioEngine::process_callback (pframes_t nframes)
}
if (_freewheeling) {
PortManager::cycle_end (nframes);
return 0;
}
if (!_running) {
PortManager::cycle_end (nframes);
_processed_frames = next_processed_frames;
return 0;
}
@ -347,10 +363,31 @@ AudioEngine::process_callback (pframes_t nframes)
last_monitor_check = next_processed_frames;
}
#ifdef SILENCE_AFTER_SECONDS
bool was_silent = (_silence_countdown == 0);
if (_silence_countdown >= nframes) {
_silence_countdown -= nframes;
} else {
_silence_countdown = 0;
}
if (!was_silent && _silence_countdown == 0) {
_silence_hit_cnt++;
BecameSilent (); /* EMIT SIGNAL */
}
if (_silence_countdown == 0 || _session->silent()) {
PortManager::silence (nframes);
}
#else
if (_session->silent()) {
PortManager::silence (nframes);
}
#endif
if (session_remove_pending && session_removal_countdown) {
PortManager::fade_out (session_removal_gain, session_removal_gain_step, nframes);
@ -373,6 +410,29 @@ AudioEngine::process_callback (pframes_t nframes)
return 0;
}
void
AudioEngine::reset_silence_countdown ()
{
#ifdef SILENCE_AFTER_SECONDS
double sr = 48000; /* default in case there is no backend */
sr = sample_rate();
_silence_countdown = max (60 * sr, /* 60 seconds */
sr * (SILENCE_AFTER_SECONDS / ::pow (2.0, (double) _silence_hit_cnt)));
#endif
}
void
AudioEngine::launch_device_control_app()
{
if (_state_lock.trylock () ) {
_backend->launch_control_app ();
_state_lock.unlock ();
}
}
void
AudioEngine::request_backend_reset()
@ -382,57 +442,60 @@ AudioEngine::request_backend_reset()
_hw_reset_condition.signal ();
}
int
AudioEngine::backend_reset_requested()
{
return g_atomic_int_get (&_hw_reset_request_count);
}
void
AudioEngine::do_reset_backend()
{
SessionEvent::create_per_thread_pool (X_("Backend reset processing thread"), 512);
SessionEvent::create_per_thread_pool (X_("Backend reset processing thread"), 512);
Glib::Threads::Mutex::Lock guard (_reset_request_lock);
Glib::Threads::Mutex::Lock guard (_reset_request_lock);
while (!_stop_hw_reset_processing) {
while (!_stop_hw_reset_processing) {
if (_hw_reset_request_count && _backend) {
if (g_atomic_int_get (&_hw_reset_request_count) != 0 && _backend) {
_reset_request_lock.unlock();
Glib::Threads::RecMutex::Lock pl (_state_lock);
g_atomic_int_dec_and_test (&_hw_reset_request_count);
std::cout << "AudioEngine::RESET::Reset request processing" << std::endl;
// backup the device name
std::string name = _backend->device_name ();
g_atomic_int_dec_and_test (&_hw_reset_request_count);
std::cout << "AudioEngine::RESET::Reset request processing. Requests left: " << _hw_reset_request_count << std::endl;
DeviceResetStarted(); // notify about device reset to be started
// backup the device name
std::string name = _backend->device_name ();
std::cout << "AudioEngine::RESET::Stoping engine..." << std::endl;
stop();
std::cout << "AudioEngine::RESET::Reseting device..." << std::endl;
if ( 0 == _backend->reset_device () ) {
std::cout << "AudioEngine::RESET::Starting engine..." << std::endl;
start ();
// inform about possible changes
BufferSizeChanged (_backend->buffer_size() );
} else {
DeviceError();
}
std::cout << "AudioEngine::RESET::Done." << std::endl;
_reset_request_lock.lock();
_reset_request_lock.lock();
} else {
} else {
_hw_reset_condition.wait (_reset_request_lock);
_hw_reset_condition.wait (_reset_request_lock);
}
}
}
}
}
void
AudioEngine::request_device_list_update()
{
@ -738,7 +801,7 @@ void
AudioEngine::drop_backend ()
{
if (_backend) {
_backend->stop ();
stop(false);
_backend->drop_device ();
_backend.reset ();
_running = false;
@ -979,7 +1042,7 @@ AudioEngine::raw_buffer_size (DataType t)
return _backend->raw_buffer_size (t);
}
pframes_t
framepos_t
AudioEngine::sample_time ()
{
if (!_backend) {
@ -988,7 +1051,7 @@ AudioEngine::sample_time ()
return _backend->sample_time ();
}
pframes_t
framepos_t
AudioEngine::sample_time_at_cycle_start ()
{
if (!_backend) {
@ -1066,6 +1129,7 @@ AudioEngine::set_sample_rate (float sr)
if (!_backend) {
return -1;
}
return _backend->set_sample_rate (sr);
}
@ -1134,11 +1198,11 @@ AudioEngine::thread_init_callback (void* arg)
pthread_set_name (X_("audioengine"));
SessionEvent::create_per_thread_pool (X_("AudioEngine"), 512);
PBD::notify_gui_about_thread_creation ("gui", pthread_self(), X_("AudioEngine"), 4096);
PBD::notify_gui_about_thread_creation ("midiui", pthread_self(), X_("AudioEngine"), 128);
SessionEvent::create_per_thread_pool (X_("AudioEngine"), 512);
AsyncMIDIPort::set_process_thread (pthread_self());
if (arg) {

View file

@ -205,12 +205,12 @@ AudioFileSource::find_broken_peakfile (string peak_path, string audio_path)
/* Nasty band-aid for older sessions that were created before we
used libsndfile for all audio files.
*/
#ifndef PLATFORM_WINDOWS // there's no old_peak_path() for windows
str = old_peak_path (audio_path);
if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
peak_path = str;
}
#endif
}
return peak_path;

View file

@ -768,7 +768,7 @@ AudioRegion::get_basic_state ()
{
XMLNode& node (Region::state ());
char buf[64];
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
snprintf (buf, sizeof (buf), "%u", (uint32_t) _sources.size());
node.add_property ("channels", buf);
@ -781,7 +781,7 @@ AudioRegion::state ()
{
XMLNode& node (get_basic_state());
XMLNode *child;
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
child = node.add_child ("Envelope");
@ -838,7 +838,7 @@ AudioRegion::_set_state (const XMLNode& node, int version, PropertyChange& what_
{
const XMLNodeList& nlist = node.children();
const XMLProperty *prop;
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
boost::shared_ptr<Playlist> the_playlist (_playlist.lock());
suspend_property_changes ();
@ -925,12 +925,12 @@ AudioRegion::_set_state (const XMLNode& node, int version, PropertyChange& what_
}
}
} else if (child->name() == "InverseFadeIn") {
} else if ( (child->name() == "InverseFadeIn") || (child->name() == "InvFadeIn") ) {
XMLNode* grandchild = child->child ("AutomationList");
if (grandchild) {
_inverse_fade_in->set_state (*grandchild, version);
}
} else if (child->name() == "InverseFadeOut") {
} else if ( (child->name() == "InverseFadeOut") || (child->name() == "InvFadeOut") ) {
XMLNode* grandchild = child->child ("AutomationList");
if (grandchild) {
_inverse_fade_out->set_state (*grandchild, version);
@ -1696,31 +1696,38 @@ in this and future transient-detection operations.\n\
}
}
TransientDetector t (pl->session().frame_rate());
bool existing_results = !results.empty();
_transients.clear ();
_valid_transients = false;
try {
for (uint32_t i = 0; i < n_channels(); ++i) {
TransientDetector t (pl->session().frame_rate());
AnalysisFeatureList these_results;
_transients.clear ();
_valid_transients = false;
t.reset ();
for (uint32_t i = 0; i < n_channels(); ++i) {
if (t.run ("", this, i, these_results)) {
return -1;
AnalysisFeatureList these_results;
t.reset ();
if (t.run ("", this, i, these_results)) {
return -1;
}
/* translate all transients to give absolute position */
for (AnalysisFeatureList::iterator i = these_results.begin(); i != these_results.end(); ++i) {
(*i) += _position;
}
/* merge */
_transients.insert (_transients.end(), these_results.begin(), these_results.end());
}
/* translate all transients to give absolute position */
for (AnalysisFeatureList::iterator i = these_results.begin(); i != these_results.end(); ++i) {
(*i) += _position;
}
/* merge */
_transients.insert (_transients.end(), these_results.begin(), these_results.end());
} catch (...) {
error << string_compose(_("Transient Analysis failed for %1."), _("Audio Region")) << endmsg;
return -1;
}
if (!results.empty()) {

View file

@ -34,10 +34,17 @@
#include <algorithm>
#include <vector>
#ifdef PLATFORM_WINDOWS
#include <windows.h>
#else
#include <sys/mman.h>
#endif
#include <glib.h>
#include <glib/gstdio.h>
#include <boost/scoped_array.hpp>
#include <boost/scoped_ptr.hpp>
#include <glibmm/fileutils.h>
@ -78,6 +85,10 @@ AudioSource::AudioSource (Session& s, string name)
, peak_leftover_cnt (0)
, peak_leftover_size (0)
, peak_leftovers (0)
, _first_run (true)
, _last_scale (0.0)
, _last_map_off (0)
, _last_raw_map_length (0)
{
}
@ -90,6 +101,10 @@ AudioSource::AudioSource (Session& s, const XMLNode& node)
, peak_leftover_cnt (0)
, peak_leftover_size (0)
, peak_leftovers (0)
, _first_run (true)
, _last_scale (0.0)
, _last_map_off (0)
, _last_raw_map_length (0)
{
if (set_state (node, Stateful::loading_state_version)) {
throw failed_constructor();
@ -331,7 +346,14 @@ AudioSource::read_peaks_with_fpp (PeakData *peaks, framecnt_t npeaks, framepos_t
PeakData::PeakDatum xmax;
PeakData::PeakDatum xmin;
int32_t to_read;
ssize_t nread;
#ifdef PLATFORM_WINDOWS
SYSTEM_INFO system_info;
GetSystemInfo (&system_info);
const int bufsize = system_info.dwAllocationGranularity;;
#else
const int bufsize = sysconf(_SC_PAGESIZE);
#endif
framecnt_t read_npeaks = npeaks;
framecnt_t zero_fill = 0;
ScopedFileDescriptor sfd (::open (peakpath.c_str(), O_RDONLY));
@ -352,12 +374,11 @@ AudioSource::read_peaks_with_fpp (PeakData *peaks, framecnt_t npeaks, framepos_t
if (cnt > _length - start) {
// cerr << "too close to end @ " << _length << " given " << start << " + " << cnt << " (" << _length - start << ")" << endl;
cnt = _length - start;
framecnt_t old = npeaks;
npeaks = min ((framecnt_t) floor (cnt / samples_per_visual_peak), npeaks);
zero_fill = old - npeaks;
read_npeaks = min ((framecnt_t) floor (cnt / samples_per_visual_peak), npeaks);
zero_fill = npeaks - read_npeaks;
}
// cerr << "actual npeaks = " << npeaks << " zf = " << zero_fill << endl;
// cerr << "actual npeaks = " << read_npeaks << " zf = " << zero_fill << endl;
if (npeaks == cnt) {
@ -383,39 +404,73 @@ AudioSource::read_peaks_with_fpp (PeakData *peaks, framecnt_t npeaks, framepos_t
}
if (scale == 1.0) {
off_t offset = 0;
off_t first_peak_byte = (start / samples_per_file_peak) * sizeof (PeakData);
ssize_t bytes_to_read = sizeof (PeakData)* npeaks;
size_t bytes_to_read = sizeof (PeakData) * read_npeaks;
/* open, read, close */
DEBUG_TRACE (DEBUG::Peaks, "DIRECT PEAKS\n");
offset = lseek (sfd, first_peak_byte, SEEK_SET);
off_t map_off = first_peak_byte;
off_t read_map_off = map_off & ~(bufsize - 1);
off_t map_delta = map_off - read_map_off;
size_t map_length = bytes_to_read + map_delta;
if (offset != first_peak_byte) {
error << string_compose(_("AudioSource: could not seek to correct location in peak file \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
return -1;
if (_first_run || (_last_scale != samples_per_visual_peak) || (_last_map_off != map_off) || (_last_raw_map_length < bytes_to_read)) {
peak_cache.reset (new PeakData[npeaks]);
char* addr;
#ifdef PLATFORM_WINDOWS
HANDLE file_handle = (HANDLE) _get_osfhandle(int(sfd));
HANDLE map_handle;
LPVOID view_handle;
bool err_flag;
map_handle = CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 0, NULL);
if (map_handle == NULL) {
error << string_compose (_("map failed - could not create file mapping for peakfile %1."), peakpath) << endmsg;
return -1;
}
view_handle = MapViewOfFile(map_handle, FILE_MAP_READ, 0, read_map_off, map_length);
if (view_handle == NULL) {
error << string_compose (_("map failed - could not map peakfile %1."), peakpath) << endmsg;
return -1;
}
addr = (char*) view_handle;
memcpy ((void*)peak_cache.get(), (void*)(addr + map_delta), bytes_to_read);
err_flag = UnmapViewOfFile (view_handle);
err_flag = CloseHandle(map_handle);
if(!err_flag) {
error << string_compose (_("unmap failed - could not unmap peakfile %1."), peakpath) << endmsg;
return -1;
}
#else
addr = (char*) mmap (0, map_length, PROT_READ, MAP_PRIVATE, sfd, read_map_off);
if (addr == MAP_FAILED) {
error << string_compose (_("map failed - could not mmap peakfile %1."), peakpath) << endmsg;
return -1;
}
memcpy ((void*)peak_cache.get(), (void*)(addr + map_delta), bytes_to_read);
munmap (addr, map_length);
#endif
if (zero_fill) {
memset (&peak_cache[read_npeaks], 0, sizeof (PeakData) * zero_fill);
}
_first_run = false;
_last_scale = samples_per_visual_peak;
_last_map_off = map_off;
_last_raw_map_length = bytes_to_read;
}
nread = ::read (sfd, peaks, bytes_to_read);
if (nread != bytes_to_read) {
DEBUG_TRACE (DEBUG::Peaks, string_compose ("[%1]: Cannot read peaks from peakfile! (read only %2 not %3 at sample %4 = byte %5 )\n"
, _name, nread, npeaks, start, first_peak_byte));
return -1;
}
if (zero_fill) {
memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
}
memcpy ((void*)peaks, (void*)peak_cache.get(), npeaks * sizeof(PeakData));
return 0;
}
framecnt_t tnp;
if (scale < 1.0) {
DEBUG_TRACE (DEBUG::Peaks, "DOWNSAMPLE\n");
@ -430,20 +485,16 @@ AudioSource::read_peaks_with_fpp (PeakData *peaks, framecnt_t npeaks, framepos_t
to avoid confusion, I'll refer to the requested peaks as visual_peaks and the peakfile peaks as stored_peaks
*/
const framecnt_t chunksize = (framecnt_t) min (expected_peaks, 65536.0);
boost::scoped_array<PeakData> staging(new PeakData[chunksize]);
const framecnt_t chunksize = (framecnt_t) expected_peaks; // we read all the peaks we need in one hit.
/* compute the rounded up frame position */
framepos_t current_frame = start;
framepos_t current_stored_peak = (framepos_t) ceil (current_frame / (double) samples_per_file_peak);
framepos_t next_visual_peak = (framepos_t) ceil (current_frame / samples_per_visual_peak);
framepos_t current_stored_peak = (framepos_t) ceil (start / (double) samples_per_file_peak);
framepos_t next_visual_peak = (framepos_t) ceil (start / samples_per_visual_peak);
double next_visual_peak_frame = next_visual_peak * samples_per_visual_peak;
framepos_t stored_peak_before_next_visual_peak = (framepos_t) next_visual_peak_frame / samples_per_file_peak;
framecnt_t nvisual_peaks = 0;
framecnt_t stored_peaks_read = 0;
framecnt_t i = 0;
uint32_t i = 0;
/* handle the case where the initial visual peak is on a pixel boundary */
@ -451,67 +502,89 @@ AudioSource::read_peaks_with_fpp (PeakData *peaks, framecnt_t npeaks, framepos_t
/* open ... close during out: handling */
while (nvisual_peaks < npeaks) {
off_t map_off = (uint32_t) (ceil (start / (double) samples_per_file_peak)) * sizeof(PeakData);
off_t read_map_off = map_off & ~(bufsize - 1);
off_t map_delta = map_off - read_map_off;
size_t raw_map_length = chunksize * sizeof(PeakData);
size_t map_length = (chunksize * sizeof(PeakData)) + map_delta;
if (i == stored_peaks_read) {
if (_first_run || (_last_scale != samples_per_visual_peak) || (_last_map_off != map_off) || (_last_raw_map_length < raw_map_length)) {
peak_cache.reset (new PeakData[npeaks]);
boost::scoped_array<PeakData> staging (new PeakData[chunksize]);
uint32_t start_byte = current_stored_peak * sizeof(PeakData);
tnp = min ((framecnt_t)(_length/samples_per_file_peak - current_stored_peak), (framecnt_t) expected_peaks);
to_read = min (chunksize, tnp);
ssize_t bytes_to_read = sizeof (PeakData) * to_read;
char* addr;
#ifdef PLATFORM_WINDOWS
HANDLE file_handle = (HANDLE) _get_osfhandle(int(sfd));
HANDLE map_handle;
LPVOID view_handle;
bool err_flag;
DEBUG_TRACE (DEBUG::Peaks, string_compose ("reading %1 bytes from peakfile @ %2\n"
, bytes_to_read, start_byte));
off_t offset = lseek (sfd, start_byte, SEEK_SET);
if (offset != start_byte) {
error << string_compose(_("AudioSource: could not seek to correct location in peak file \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
return -1;
}
if ((nread = ::read (sfd, staging.get(), bytes_to_read)) != bytes_to_read) {
off_t fend = lseek (sfd, 0, SEEK_END);
DEBUG_TRACE (DEBUG::Peaks, string_compose ("[%1]: cannot read peak data from peakfile (%2 peaks instead of %3) (%4) at start_byte = %5 _length = %6 versus len = %7 expected maxpeaks = %8 npeaks was %9"
, _name, (nread / sizeof(PeakData)), to_read, g_strerror (errno), start_byte, _length, fend, ((_length - current_frame)/samples_per_file_peak), npeaks));
return -1;
}
i = 0;
stored_peaks_read = nread / sizeof(PeakData);
map_handle = CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 0, NULL);
if (map_handle == NULL) {
error << string_compose (_("map failed - could not create file mapping for peakfile %1."), peakpath) << endmsg;
return -1;
}
xmax = -1.0;
xmin = 1.0;
while ((i < stored_peaks_read) && (current_stored_peak <= stored_peak_before_next_visual_peak)) {
xmax = max (xmax, staging[i].max);
xmin = min (xmin, staging[i].min);
++i;
++current_stored_peak;
--expected_peaks;
view_handle = MapViewOfFile(map_handle, FILE_MAP_READ, 0, read_map_off, map_length);
if (view_handle == NULL) {
error << string_compose (_("map failed - could not map peakfile %1."), peakpath) << endmsg;
return -1;
}
peaks[nvisual_peaks].max = xmax;
peaks[nvisual_peaks].min = xmin;
++nvisual_peaks;
++next_visual_peak;
addr = (char *) view_handle;
//next_visual_peak_frame = min ((next_visual_peak * samples_per_visual_peak), (next_visual_peak_frame+samples_per_visual_peak) );
next_visual_peak_frame = min ((double) start+cnt, (next_visual_peak_frame+samples_per_visual_peak) );
stored_peak_before_next_visual_peak = (uint32_t) next_visual_peak_frame / samples_per_file_peak;
memcpy ((void*)staging.get(), (void*)(addr + map_delta), raw_map_length);
err_flag = UnmapViewOfFile (view_handle);
err_flag = CloseHandle(map_handle);
if(!err_flag) {
error << string_compose (_("unmap failed - could not unmap peakfile %1."), peakpath) << endmsg;
return -1;
}
#else
addr = (char*) mmap (0, map_length, PROT_READ, MAP_PRIVATE, sfd, read_map_off);
if (addr == MAP_FAILED) {
error << string_compose (_("map failed - could not mmap peakfile %1."), peakpath) << endmsg;
return -1;
}
memcpy ((void*)staging.get(), (void*)(addr + map_delta), raw_map_length);
munmap (addr, map_length);
#endif
while (nvisual_peaks < read_npeaks) {
xmax = -1.0;
xmin = 1.0;
while ((current_stored_peak <= stored_peak_before_next_visual_peak) && (i < chunksize)) {
xmax = max (xmax, staging[i].max);
xmin = min (xmin, staging[i].min);
++i;
++current_stored_peak;
}
peak_cache[nvisual_peaks].max = xmax;
peak_cache[nvisual_peaks].min = xmin;
++nvisual_peaks;
next_visual_peak_frame = min ((double) start + cnt, (next_visual_peak_frame + samples_per_visual_peak));
stored_peak_before_next_visual_peak = (uint32_t) next_visual_peak_frame / samples_per_file_peak;
}
if (zero_fill) {
cerr << "Zero fill end of peaks (@ " << read_npeaks << " with " << zero_fill << ")" << endl;
memset (&peak_cache[read_npeaks], 0, sizeof (PeakData) * zero_fill);
}
_first_run = false;
_last_scale = samples_per_visual_peak;
_last_map_off = map_off;
_last_raw_map_length = raw_map_length;
}
if (zero_fill) {
cerr << "Zero fill end of peaks (@ " << npeaks << " with " << zero_fill << endl;
memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
}
memcpy ((void*)peaks, (void*)peak_cache.get(), npeaks * sizeof(PeakData));
} else {
DEBUG_TRACE (DEBUG::Peaks, "UPSAMPLE\n");
/* the caller wants
@ -538,7 +611,7 @@ AudioSource::read_peaks_with_fpp (PeakData *peaks, framecnt_t npeaks, framepos_t
xmin = 1.0;
xmax = -1.0;
while (nvisual_peaks < npeaks) {
while (nvisual_peaks < read_npeaks) {
if (i == frames_read) {
@ -549,7 +622,7 @@ AudioSource::read_peaks_with_fpp (PeakData *peaks, framecnt_t npeaks, framepos_t
/* hmm, error condition - we've reached the end of the file
without generating all the peak data. cook up a zero-filled
data buffer and then use it. this is simpler than
adjusting zero_fill and npeaks and then breaking out of
adjusting zero_fill and read_npeaks and then breaking out of
this loop early
*/
@ -590,7 +663,7 @@ AudioSource::read_peaks_with_fpp (PeakData *peaks, framecnt_t npeaks, framepos_t
}
if (zero_fill) {
memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
memset (&peaks[read_npeaks], 0, sizeof (PeakData) * zero_fill);
}
}

View file

@ -429,7 +429,7 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
if (!_synth_added && asynth) {
int rv = add_processor_by_index(asynth, PreFader, &ps, true);
int rv = add_processor (asynth, PreFader, &ps, true);
if (rv) {
error << _("Failed to load synth for MIDI-Audition.") << endmsg;
} else {
@ -514,7 +514,7 @@ Auditioner::play_audition (framecnt_t nframes)
if(!_seeking) {
/* process audio */
this_nframes = min (nframes, length - current_frame);
this_nframes = min (nframes, length - current_frame + _import_position);
if ((ret = roll (this_nframes, current_frame, current_frame + nframes, false, need_butler)) != 0) {
silence (nframes);
@ -538,7 +538,7 @@ Auditioner::play_audition (framecnt_t nframes)
AuditionProgress(current_frame - _import_position, length); /* emit */
}
if (current_frame >= length) {
if (current_frame >= length + _import_position) {
_session.cancel_audition ();
return 0;
} else {

View file

@ -173,8 +173,10 @@ Automatable::describe_parameter (Evoral::Parameter param)
return string_compose("Bender [%1]", int(param.channel()) + 1);
} else if (param.type() == MidiChannelPressureAutomation) {
return string_compose("Pressure [%1]", int(param.channel()) + 1);
#ifdef LV2_SUPPORT
} else if (param.type() == PluginPropertyAutomation) {
return string_compose("Property %1", URIMap::instance().id_to_uri(param.id()));
#endif
} else {
return EventTypeMap::instance().to_symbol(param);
}

View file

@ -253,7 +253,7 @@ AutomationList::state (bool full)
{
XMLNode* root = new XMLNode (X_("AutomationList"));
char buf[64];
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
root->add_property ("automation-id", EventTypeMap::instance().to_symbol(_parameter));
@ -367,7 +367,7 @@ AutomationList::deserialize_events (const XMLNode& node)
int
AutomationList::set_state (const XMLNode& node, int version)
{
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
XMLNodeList nlist = node.children();
XMLNode* nsos;
XMLNodeIterator niter;

View file

@ -44,6 +44,7 @@ AutomationWatch::instance ()
AutomationWatch::AutomationWatch ()
: _thread (0)
, _last_time (0)
, _run_thread (false)
{
@ -121,12 +122,25 @@ AutomationWatch::timer ()
Glib::Threads::Mutex::Lock lm (automation_watch_lock);
framepos_t time = _session->audible_frame ();
for (AutomationWatches::iterator aw = automation_watches.begin(); aw != automation_watches.end(); ++aw) {
if ((*aw)->alist()->automation_write()) {
(*aw)->list()->add (time, (*aw)->user_double(), true);
if (time > _last_time) { //we only write automation in the forward direction; this fixes automation-recording in a loop
for (AutomationWatches::iterator aw = automation_watches.begin(); aw != automation_watches.end(); ++aw) {
if ((*aw)->alist()->automation_write()) {
(*aw)->list()->add (time, (*aw)->user_double(), true);
}
}
} else { //transport stopped or reversed. stop the automation pass and start a new one (for bonus points, someday store the previous pass in an undo record)
for (AutomationWatches::iterator aw = automation_watches.begin(); aw != automation_watches.end(); ++aw) {
DEBUG_TRACE (DEBUG::Automation, string_compose ("%1: transport in rewind, speed %2, in write pass ? %3 writing ? %4\n",
(*aw)->name(), _session->transport_speed(), _session->transport_rolling(),
(*aw)->alist()->automation_write()));
(*aw)->list()->set_in_write_pass (false);
if ( (*aw)->alist()->automation_write() ) {
(*aw)->list()->set_in_write_pass (true);
}
}
}
_last_time = time;
}
return TRUE;
@ -170,6 +184,8 @@ AutomationWatch::transport_state_change ()
}
bool rolling = _session->transport_rolling();
_last_time = _session->audible_frame ();
{
Glib::Threads::Mutex::Lock lm (automation_watch_lock);

View file

@ -31,9 +31,9 @@ namespace ARDOUR {
* taking tempo changes into account.
*/
framepos_t
BeatsFramesConverter::to (Evoral::MusicalTime beats) const
BeatsFramesConverter::to (Evoral::Beats beats) const
{
if (beats < Evoral::MusicalTime()) {
if (beats < Evoral::Beats()) {
std::cerr << "negative beats passed to BFC: " << beats << std::endl;
PBD::stacktrace (std::cerr, 30);
return 0;
@ -45,7 +45,7 @@ BeatsFramesConverter::to (Evoral::MusicalTime beats) const
* supplied to the constructor. Returns the equivalent number of beats,
* taking tempo changes into account.
*/
Evoral::MusicalTime
Evoral::Beats
BeatsFramesConverter::from (framepos_t frames) const
{
return _tempo_map.framewalk_to_beats (_origin_b, frames);
@ -60,7 +60,7 @@ DoubleBeatsFramesConverter::to (double beats) const
PBD::stacktrace (std::cerr, 30);
return 0;
}
return _tempo_map.framepos_plus_beats (_origin_b, Evoral::MusicalTime(beats)) - _origin_b;
return _tempo_map.framepos_plus_beats (_origin_b, Evoral::Beats(beats)) - _origin_b;
}
/** As above, but with beats in double instead (for GUI). */

View file

@ -49,6 +49,7 @@ Butler::Butler(Session& s)
, audio_dstream_playback_buffer_size(0)
, midi_dstream_buffer_size(0)
, pool_trash(16)
, _xthread (true)
{
g_atomic_int_set(&should_do_transport_work, 0);
SessionEvent::pool->set_trash (&pool_trash);
@ -64,41 +65,18 @@ Butler::~Butler()
void
Butler::config_changed (std::string p)
{
if (p == "playback-buffer-seconds") {
/* size is in Samples, not bytes */
audio_dstream_playback_buffer_size = (uint32_t) floor (Config->get_audio_playback_buffer_seconds() * _session.frame_rate());
_session.adjust_playback_buffering ();
} else if (p == "capture-buffer-seconds") {
audio_dstream_capture_buffer_size = (uint32_t) floor (Config->get_audio_capture_buffer_seconds() * _session.frame_rate());
_session.adjust_capture_buffering ();
}
if (p == "playback-buffer-seconds") {
/* size is in Samples, not bytes */
audio_dstream_playback_buffer_size = (uint32_t) floor (Config->get_audio_playback_buffer_seconds() * _session.frame_rate());
_session.adjust_playback_buffering ();
} else if (p == "capture-buffer-seconds") {
audio_dstream_capture_buffer_size = (uint32_t) floor (Config->get_audio_capture_buffer_seconds() * _session.frame_rate());
_session.adjust_capture_buffering ();
} else if (p == "midi-readahead") {
MidiDiskstream::set_readahead_frames ((framecnt_t) (Config->get_midi_readahead() * _session.frame_rate()));
}
}
#ifndef PLATFORM_WINDOWS
int
Butler::setup_request_pipe ()
{
if (pipe (request_pipe)) {
error << string_compose(_("Cannot create transport request signal pipe (%1)"),
strerror (errno)) << endmsg;
return -1;
}
if (fcntl (request_pipe[0], F_SETFL, O_NONBLOCK)) {
error << string_compose(_("UI: cannot set O_NONBLOCK on butler request pipe (%1)"),
strerror (errno)) << endmsg;
return -1;
}
if (fcntl (request_pipe[1], F_SETFL, O_NONBLOCK)) {
error << string_compose(_("UI: cannot set O_NONBLOCK on butler request pipe (%1)"),
strerror (errno)) << endmsg;
return -1;
}
return 0;
}
#endif
int
Butler::start_thread()
{
@ -118,10 +96,6 @@ Butler::start_thread()
should_run = false;
#ifndef PLATFORM_WINDOWS
if (setup_request_pipe() != 0) return -1;
#endif
if (pthread_create_and_store ("disk butler", &thread, _thread_work, this)) {
error << _("Session: could not create butler thread") << endmsg;
return -1;
@ -151,69 +125,6 @@ Butler::_thread_work (void* arg)
return ((Butler *) arg)->thread_work ();
}
bool
Butler::wait_for_requests ()
{
#ifndef PLATFORM_WINDOWS
struct pollfd pfd[1];
pfd[0].fd = request_pipe[0];
pfd[0].events = POLLIN|POLLERR|POLLHUP;
while(true) {
if (poll (pfd, 1, -1) < 0) {
if (errno == EINTR) {
continue;
}
error << string_compose (_("poll on butler request pipe failed (%1)"),
strerror (errno))
<< endmsg;
break;
}
DEBUG_TRACE (DEBUG::Butler, string_compose ("%1: butler awake at @ %2\n", DEBUG_THREAD_SELF, g_get_monotonic_time()));
if (pfd[0].revents & ~POLLIN) {
error << string_compose (_("Error on butler thread request pipe: fd=%1 err=%2"), pfd[0].fd, pfd[0].revents) << endmsg;
break;
}
if (pfd[0].revents & POLLIN) {
return true;
}
}
return false;
#else
m_request_sem.wait ();
return true;
#endif
}
bool
Butler::dequeue_request (Request::Type& r)
{
#ifndef PLATFORM_WINDOWS
char req;
size_t nread = ::read (request_pipe[0], &req, sizeof (req));
if (nread == 1) {
r = (Request::Type) req;
return true;
} else if (nread == 0) {
return false;
} else if (errno == EAGAIN) {
return false;
} else {
fatal << _("Error reading from butler request pipe") << endmsg;
abort(); /*NOTREACHED*/
}
#else
r = (Request::Type) m_request_state.get();
#endif
return false;
}
void *
Butler::thread_work ()
{
@ -227,16 +138,12 @@ Butler::thread_work ()
if(!disk_work_outstanding) {
DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 butler waits for requests @ %2\n", DEBUG_THREAD_SELF, g_get_monotonic_time()));
if (wait_for_requests ()) {
Request::Type req;
/* empty the pipe of all current requests */
#ifdef PLATFORM_WINDOWS
dequeue_request (req);
#else
while (dequeue_request(req)) {
#endif
switch (req) {
char msg;
/* empty the pipe of all current requests */
if (_xthread.receive (msg, true) >= 0) {
Request::Type req = (Request::Type) msg;
switch (req) {
case Request::Run:
DEBUG_TRACE (DEBUG::Butler, string_compose ("%1: butler asked to run @ %2\n", DEBUG_THREAD_SELF, g_get_monotonic_time()));
@ -256,10 +163,7 @@ Butler::thread_work ()
default:
break;
}
#ifndef PLATFORM_WINDOWS
}
#endif
}
}
@ -425,13 +329,20 @@ Butler::schedule_transport_work ()
void
Butler::queue_request (Request::Type r)
{
#ifndef PLATFORM_WINDOWS
char c = r;
(void) ::write (request_pipe[1], &c, 1);
#else
m_request_state.set (r);
m_request_sem.post ();
#endif
if (_xthread.deliver (c) != 1) {
/* the x-thread channel is non-blocking
* write may fail, but we really don't want to wait
* under normal circumstances.
*
* a lost "run" requests under normal RT operation
* is mostly harmless.
*
* TODO if ardour is freehweeling, wait & retry.
* ditto for Request::Type Quit
*/
assert(1); // we're screwd
}
}
void

View file

@ -262,8 +262,7 @@ Delivery::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pf
if (tgain != _current_gain) {
/* target gain has changed */
Amp::apply_gain (bufs, nframes, _current_gain, tgain);
_current_gain = tgain;
_current_gain = Amp::apply_gain (bufs, _session.nominal_frame_rate(), nframes, _current_gain, tgain);
} else if (tgain == 0.0) {

View file

@ -40,12 +40,4 @@ const char* const ladspa_dir_name = X_("ladspa");
const char* const panner_dir_name = X_("panners");
const char* const backend_dir_name = X_("backends");
char config_dir_name[] = X_(PROGRAM_NAME PROGRAM_VERSION);
#if defined (__APPLE__) || defined (PLATFORM_WINDOWS)
const char* const user_config_dir_name = config_dir_name;
#else
#include "pbd/convert.h"
const char* const user_config_dir_name = PBD::downcase (config_dir_name);
#endif
}

View file

@ -53,12 +53,8 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
/* XXX This goes uninitialized when there is no ~/.config/ardour3 directory.
* I can't figure out why, so this will do for now (just stole the
* default from configuration_vars.h). 0 is not a good value for
* allocating buffer sizes..
*/
ARDOUR::framecnt_t Diskstream::disk_io_chunk_frames = 1024 * 256 / sizeof (Sample);
ARDOUR::framecnt_t Diskstream::disk_read_chunk_frames = default_disk_read_chunk_frames ();
ARDOUR::framecnt_t Diskstream::disk_write_chunk_frames = default_disk_write_chunk_frames ();
PBD::Signal0<void> Diskstream::DiskOverrun;
PBD::Signal0<void> Diskstream::DiskUnderrun;
@ -462,7 +458,7 @@ Diskstream::get_state ()
{
XMLNode* node = new XMLNode ("Diskstream");
char buf[64];
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
node->add_property ("flags", enum_2_string (_flags));
node->add_property ("playlist", _playlist->name());
@ -772,3 +768,15 @@ Diskstream::disengage_record_enable ()
{
g_atomic_int_set (&_record_enabled, 0);
}
framecnt_t
Diskstream::default_disk_read_chunk_frames()
{
return 65536;
}
framecnt_t
Diskstream::default_disk_write_chunk_frames ()
{
return 65536;
}

View file

@ -85,6 +85,7 @@ setup_enum_writer ()
ShuttleUnits _ShuttleUnits;
Session::RecordState _Session_RecordState;
SessionEvent::Type _SessionEvent_Type;
SessionEvent::Action _SessionEvent_Action;
TimecodeFormat _Session_TimecodeFormat;
Session::PullupFormat _Session_PullupFormat;
FadeShape _FadeShape;
@ -382,6 +383,12 @@ setup_enum_writer ()
REGISTER_CLASS_ENUM (SessionEvent, AutoLoopDeclick);
REGISTER (_SessionEvent_Type);
REGISTER_CLASS_ENUM (SessionEvent, Add);
REGISTER_CLASS_ENUM (SessionEvent, Remove);
REGISTER_CLASS_ENUM (SessionEvent, Replace);
REGISTER_CLASS_ENUM (SessionEvent, Clear);
REGISTER (_SessionEvent_Action);
REGISTER_CLASS_ENUM (Session, Stopped);
REGISTER_CLASS_ENUM (Session, Waiting);
REGISTER_CLASS_ENUM (Session, Running);

View file

@ -41,7 +41,11 @@ EventTypeMap&
EventTypeMap::instance()
{
if (!EventTypeMap::event_type_map) {
EventTypeMap::event_type_map = new EventTypeMap(URIMap::instance());
#ifdef LV2_SUPPORT
EventTypeMap::event_type_map = new EventTypeMap(&URIMap::instance());
#else
EventTypeMap::event_type_map = new EventTypeMap(NULL);
#endif
}
return *EventTypeMap::event_type_map;
}
@ -149,14 +153,16 @@ EventTypeMap::from_symbol(const string& str) const
} else if (str.length() > 10 && str.substr(0, 10) == "parameter-") {
p_type = PluginAutomation;
p_id = atoi(str.c_str()+10);
#ifdef LV2_SUPPORT
} else if (str.length() > 9 && str.substr(0, 9) == "property-") {
p_type = PluginPropertyAutomation;
const char* name = str.c_str() + 9;
if (isdigit(str.c_str()[0])) {
p_id = atoi(name);
} else {
p_id = _uri_map.uri_to_id(name);
p_id = _uri_map->uri_to_id(name);
}
#endif
} else if (str.length() > 7 && str.substr(0, 7) == "midicc-") {
p_type = MidiCCAutomation;
uint32_t channel = 0;
@ -223,13 +229,15 @@ EventTypeMap::to_symbol(const Evoral::Parameter& param) const
return "envelope";
} else if (t == PluginAutomation) {
return string_compose("parameter-%1", param.id());
#ifdef LV2_SUPPORT
} else if (t == PluginPropertyAutomation) {
const char* uri = _uri_map.id_to_uri(param.id());
const char* uri = _uri_map->id_to_uri(param.id());
if (uri) {
return string_compose("property-%1", uri);
} else {
return string_compose("property-%1", param.id());
}
#endif
} else if (t == MidiCCAutomation) {
return string_compose("midicc-%1-%2", int(param.channel()), param.id());
} else if (t == MidiPgmChangeAutomation) {

View file

@ -56,7 +56,9 @@ ExportFilename::ExportFilename (Session & session) :
include_time (false),
include_date (false),
session (session),
revision (1)
revision (1),
date_format (D_None),
time_format (T_None)
{
time_t rawtime;
std::time (&rawtime);

View file

@ -520,10 +520,25 @@ ExportHandler::write_cue_header (CDMarkerStatus & status)
{
string title = status.timespan->name().compare ("Session") ? status.timespan->name() : (string) session.name();
// Album metadata
string barcode = SessionMetadata::Metadata()->barcode();
string album_artist = SessionMetadata::Metadata()->album_artist();
string album_title = SessionMetadata::Metadata()->album();
status.out << "REM Cue file generated by " << PROGRAM_NAME << endl;
if (barcode != "")
status.out << "CATALOG " << barcode << endl;
if (album_artist != "")
status.out << "PERFORMER " << cue_escape_cdtext (album_artist) << endl;
if (album_title != "")
title = album_title;
status.out << "TITLE " << cue_escape_cdtext (title) << endl;
/* The original cue sheet sepc metions five file types
/* The original cue sheet spec mentions five file types
WAVE, AIFF,
BINARY = "header-less" audio (44.1 kHz, 16 Bit, little endian),
MOTOROLA = "header-less" audio (44.1 kHz, 16 Bit, big endian),
@ -556,10 +571,22 @@ ExportHandler::write_toc_header (CDMarkerStatus & status)
{
string title = status.timespan->name().compare ("Session") ? status.timespan->name() : (string) session.name();
// Album metadata
string barcode = SessionMetadata::Metadata()->barcode();
string album_artist = SessionMetadata::Metadata()->album_artist();
string album_title = SessionMetadata::Metadata()->album();
if (barcode != "")
status.out << "CATALOG " << barcode << endl;
if (album_title != "")
title = album_title;
status.out << "CD_DA" << endl;
status.out << "CD_TEXT {" << endl << " LANGUAGE_MAP {" << endl << " 0 : EN" << endl << " }" << endl;
status.out << " LANGUAGE 0 {" << endl << " TITLE " << toc_escape_cdtext (title) << endl ;
status.out << " PERFORMER \"\"" << endl << " }" << endl << "}" << endl;
status.out << " PERFORMER \"" << toc_escape_cdtext (album_artist) << "\"" << endl;
status.out << " }" << endl << "}" << endl;
}
void

View file

@ -19,8 +19,9 @@
#include <cstdlib>
#include <iostream>
#include "pbd/error.h"
#include "pbd/compose.h"
#include "pbd/convert.h"
#include "pbd/error.h"
#include <glibmm/miscutils.h>
#include <glibmm/fileutils.h>
@ -41,12 +42,26 @@ namespace ARDOUR {
using std::string;
std::string
user_config_directory ()
static std::string
user_config_directory_name (int version = -1)
{
static std::string p;
if (version < 0) {
version = atoi (X_(PROGRAM_VERSION));
}
if (!p.empty()) return p;
const string config_dir_name = string_compose ("%1%2", X_(PROGRAM_NAME), version);
#if defined (__APPLE__) || defined (PLATFORM_WINDOWS)
return config_dir_name;
#else
return downcase (config_dir_name);
#endif
}
std::string
user_config_directory (int version)
{
std::string p;
#ifdef __APPLE__
@ -79,18 +94,23 @@ user_config_directory ()
}
#endif // end not __APPLE__
p = Glib::build_filename (p, user_config_dir_name);
p = Glib::build_filename (p, user_config_directory_name (version));
if (!Glib::file_test (p, Glib::FILE_TEST_EXISTS)) {
if (g_mkdir_with_parents (p.c_str(), 0755)) {
error << string_compose (_("Cannot create Configuration directory %1 - cannot run"),
p) << endmsg;
if (version < 0) {
/* Only create the user config dir if the version was negative,
meaning "for the current version.
*/
if (!Glib::file_test (p, Glib::FILE_TEST_EXISTS)) {
if (g_mkdir_with_parents (p.c_str(), 0755)) {
error << string_compose (_("Cannot create Configuration directory %1 - cannot run"),
p) << endmsg;
exit (1);
}
} else if (!Glib::file_test (p, Glib::FILE_TEST_IS_DIR)) {
error << string_compose (_("Configuration directory %1 already exists and is not a directory/folder - cannot run"),
p) << endmsg;
exit (1);
}
} else if (!Glib::file_test (p, Glib::FILE_TEST_IS_DIR)) {
error << string_compose (_("Configuration directory %1 already exists and is not a directory/folder - cannot run"),
p) << endmsg;
exit (1);
}
return p;
@ -134,7 +154,7 @@ user_cache_directory ()
}
#endif // end not __APPLE__
p = Glib::build_filename (p, user_config_dir_name);
p = Glib::build_filename (p, user_config_directory_name ());
#ifdef PLATFORM_WINDOWS
/* On Windows Glib::get_user_data_dir is the folder to use for local
@ -252,4 +272,15 @@ ardour_data_search_path ()
return search_path;
}
string
been_here_before_path (int version)
{
if (version < 0) {
version = atoi (PROGRAM_VERSION);
}
return Glib::build_filename (user_config_directory (version), string (".a") + to_string (version, std::dec));
}
} // namespace ARDOUR

View file

@ -59,7 +59,9 @@ Filter::make_new_sources (boost::shared_ptr<Region> region, SourceList& nsrcs, s
}
}
string path = session.new_audio_source_path (name, region->n_channels(), i, false, false);
const string path = (region->data_type() == DataType::MIDI)
? session.new_midi_source_path (name)
: session.new_audio_source_path (name, region->n_channels(), i, false, false);
if (path.empty()) {
error << string_compose (_("filter: error creating name for new file based on %1"), region->name())

View file

@ -37,6 +37,10 @@
#include <errno.h>
#include <time.h>
#ifdef PLATFORM_WINDOWS
#include <windows.h> // for LARGE_INTEGER
#endif
#ifdef WINDOWS_VST_SUPPORT
#include <fst.h>
#endif
@ -85,6 +89,7 @@
#include "ardour/audioregion.h"
#include "ardour/buffer_manager.h"
#include "ardour/control_protocol_manager.h"
#include "ardour/directory_names.h"
#include "ardour/event_type_map.h"
#include "ardour/filesystem_paths.h"
#include "ardour/midi_region.h"
@ -131,6 +136,9 @@ PBD::Signal1<void,std::string> ARDOUR::BootMessage;
PBD::Signal3<void,std::string,std::string,bool> ARDOUR::PluginScanMessage;
PBD::Signal1<void,int> ARDOUR::PluginScanTimeout;
PBD::Signal0<void> ARDOUR::GUIIdle;
PBD::Signal3<bool,std::string,std::string,int> ARDOUR::CopyConfigurationFiles;
static bool have_old_configuration_files = false;
namespace ARDOUR {
extern void setup_enum_writer ();
@ -238,6 +246,132 @@ lotsa_files_please ()
#endif
}
static int
copy_configuration_files (string const & old_dir, string const & new_dir, int old_version)
{
string old_name;
string new_name;
/* ensure target directory exists */
if (g_mkdir_with_parents (new_dir.c_str(), 0755)) {
return -1;
}
if (old_version == 3) {
old_name = Glib::build_filename (old_dir, X_("recent"));
new_name = Glib::build_filename (new_dir, X_("recent"));
copy_file (old_name, new_name);
old_name = Glib::build_filename (old_dir, X_("sfdb"));
new_name = Glib::build_filename (new_dir, X_("sfdb"));
copy_file (old_name, new_name);
/* can only copy ardour.rc/config - UI config is not compatible */
/* users who have been using git/nightlies since the last
* release of 3.5 will have $CONFIG/config rather than
* $CONFIG/ardour.rc. Pick up the newer "old" config file,
* to avoid confusion.
*/
string old_name = Glib::build_filename (old_dir, X_("config"));
if (!Glib::file_test (old_name, Glib::FILE_TEST_EXISTS)) {
old_name = Glib::build_filename (old_dir, X_("ardour.rc"));
}
new_name = Glib::build_filename (new_dir, X_("config"));
copy_file (old_name, new_name);
/* copy templates and route templates */
old_name = Glib::build_filename (old_dir, X_("templates"));
new_name = Glib::build_filename (new_dir, X_("templates"));
copy_recurse (old_name, new_name);
old_name = Glib::build_filename (old_dir, X_("route_templates"));
new_name = Glib::build_filename (new_dir, X_("route_templates"));
copy_recurse (old_name, new_name);
/* presets */
old_name = Glib::build_filename (old_dir, X_("presets"));
new_name = Glib::build_filename (new_dir, X_("presets"));
copy_recurse (old_name, new_name);
/* presets */
old_name = Glib::build_filename (old_dir, X_("plugin_statuses"));
new_name = Glib::build_filename (new_dir, X_("plugin_statuses"));
copy_file (old_name, new_name);
/* export formats */
old_name = Glib::build_filename (old_dir, export_formats_dir_name);
new_name = Glib::build_filename (new_dir, export_formats_dir_name);
vector<string> export_formats;
g_mkdir_with_parents (Glib::build_filename (new_dir, export_formats_dir_name).c_str(), 0755);
find_files_matching_pattern (export_formats, old_name, X_("*.format"));
for (vector<string>::iterator i = export_formats.begin(); i != export_formats.end(); ++i) {
std::string from = *i;
std::string to = Glib::build_filename (new_name, Glib::path_get_basename (*i));
copy_file (from, to);
}
}
return 0;
}
void
ARDOUR::check_for_old_configuration_files ()
{
int current_version = atoi (X_(PROGRAM_VERSION));
if (current_version <= 1) {
return;
}
int old_version = current_version - 1;
string old_config_dir = user_config_directory (old_version);
/* pass in the current version explicitly to avoid creation */
string current_config_dir = user_config_directory (current_version);
if (!Glib::file_test (current_config_dir, Glib::FILE_TEST_IS_DIR)) {
if (Glib::file_test (old_config_dir, Glib::FILE_TEST_IS_DIR)) {
have_old_configuration_files = true;
}
}
}
int
ARDOUR::handle_old_configuration_files (boost::function<bool (std::string const&, std::string const&, int)> ui_handler)
{
if (have_old_configuration_files) {
int current_version = atoi (X_(PROGRAM_VERSION));
assert (current_version > 1); // established in check_for_old_configuration_files ()
int old_version = current_version - 1;
string old_config_dir = user_config_directory (old_version);
string current_config_dir = user_config_directory (current_version);
if (ui_handler (old_config_dir, current_config_dir, old_version)) {
copy_configuration_files (old_config_dir, current_config_dir, old_version);
return 1;
}
}
return 0;
}
bool
ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir)
{
@ -328,7 +462,9 @@ ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir
/* singletons - first object is "it" */
(void) PluginManager::instance();
#ifdef LV2_SUPPORT
(void) URIMap::instance();
#endif
(void) EventTypeMap::instance();
ProcessThread::init ();
@ -609,3 +745,26 @@ ARDOUR::get_microseconds ()
return (microseconds_t) ts.tv_sec * 1000000 + (ts.tv_nsec/1000);
#endif
}
/** Return the number of bits per sample for a given sample format.
*
* This is closely related to sndfile_data_width() but does NOT
* return a "magic" value to differentiate between 32 bit integer
* and 32 bit floating point values.
*/
int
ARDOUR::format_data_width (ARDOUR::SampleFormat format)
{
switch (format) {
case ARDOUR::FormatInt16:
return 16;
case ARDOUR::FormatInt24:
return 24;
default:
return 32;
}
}

View file

@ -53,7 +53,7 @@ int alloc_allowed ()
Graph::Graph (Session & session)
: SessionHandleRef (session)
, _quit_threads (false)
, _threads_active (false)
, _execution_sem ("graph_execution", 0)
, _callback_start_sem ("graph_start", 0)
, _callback_done_sem ("graph_done", 0)
@ -71,9 +71,13 @@ Graph::Graph (Session & session)
_current_chain = 0;
_pending_chain = 0;
_setup_chain = 1;
_quit_threads = false;
_graph_empty = true;
ARDOUR::AudioEngine::instance()->Running.connect_same_thread (engine_connections, boost::bind (&Graph::reset_thread_list, this));
ARDOUR::AudioEngine::instance()->Stopped.connect_same_thread (engine_connections, boost::bind (&Graph::engine_stopped, this));
ARDOUR::AudioEngine::instance()->Halted.connect_same_thread (engine_connections, boost::bind (&Graph::engine_stopped, this));
reset_thread_list ();
#ifdef DEBUG_RT_ALLOC
@ -82,6 +86,14 @@ Graph::Graph (Session & session)
#endif
}
void
Graph::engine_stopped ()
{
if (AudioEngine::instance()->process_thread_count() != 0) {
drop_threads ();
}
}
/** Set up threads for running the graph */
void
Graph::reset_thread_list ()
@ -114,6 +126,7 @@ Graph::reset_thread_list ()
throw failed_constructor ();
}
}
_threads_active = true;
}
void
@ -132,7 +145,7 @@ Graph::session_going_away()
void
Graph::drop_threads ()
{
_quit_threads = true;
_threads_active = false;
uint32_t thread_count = AudioEngine::instance()->process_thread_count ();
@ -145,8 +158,6 @@ Graph::drop_threads ()
AudioEngine::instance()->join_process_threads ();
_execution_tokens = 0;
_quit_threads = false;
}
void
@ -243,7 +254,7 @@ Graph::restart_cycle()
/* Block until the a process callback triggers us */
_callback_start_sem.wait();
if (_quit_threads) {
if (!_threads_active) {
return;
}
@ -368,7 +379,7 @@ Graph::run_one()
pthread_mutex_unlock (&_trigger_mutex);
DEBUG_TRACE (DEBUG::ProcessThreads, string_compose ("%1 goes to sleep\n", pthread_name()));
_execution_sem.wait ();
if (_quit_threads) {
if (!_threads_active) {
return true;
}
DEBUG_TRACE (DEBUG::ProcessThreads, string_compose ("%1 is awake\n", pthread_name()));
@ -421,13 +432,13 @@ Graph::main_thread()
DEBUG_TRACE(DEBUG::ProcessThreads, "main thread is awake\n");
if (_quit_threads) {
if (!_threads_active) {
return;
}
prep ();
if (_graph_empty && !_quit_threads) {
if (_graph_empty && _threads_active) {
_callback_done_sem.signal ();
DEBUG_TRACE(DEBUG::ProcessThreads, "main thread sees graph done, goes back to sleep\n");
goto again;
@ -474,6 +485,8 @@ Graph::dump (int chain)
int
Graph::silent_process_routes (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool& need_butler)
{
if (!_threads_active) return 0;
_process_nframes = nframes;
_process_start_frame = start_frame;
_process_end_frame = end_frame;
@ -499,6 +512,8 @@ Graph::process_routes (pframes_t nframes, framepos_t start_frame, framepos_t end
{
DEBUG_TRACE (DEBUG::ProcessThreads, string_compose ("graph execution from %1 to %2 = %3\n", start_frame, end_frame, nframes));
if (!_threads_active) return 0;
_process_nframes = nframes;
_process_start_frame = start_frame;
_process_end_frame = end_frame;
@ -526,6 +541,8 @@ Graph::routes_no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end
{
DEBUG_TRACE (DEBUG::ProcessThreads, string_compose ("no-roll graph execution from %1 to %2 = %3\n", start_frame, end_frame, nframes));
if (!_threads_active) return 0;
_process_nframes = nframes;
_process_start_frame = start_frame;
_process_end_frame = end_frame;

View file

@ -392,9 +392,9 @@ write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status,
smfs->append_event_beats(
source_lock,
Evoral::Event<Evoral::MusicalTime>(
Evoral::Event<Evoral::Beats>(
0,
Evoral::MusicalTime::ticks_at_rate(t, source->ppqn()),
Evoral::Beats::ticks_at_rate(t, source->ppqn()),
size,
buf));
@ -407,9 +407,9 @@ write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status,
/* we wrote something */
const framepos_t pos = 0;
const Evoral::MusicalTime length_beats = Evoral::MusicalTime::ticks_at_rate(t, source->ppqn());
BeatsFramesConverter converter(smfs->session().tempo_map(), pos);
const framepos_t pos = 0;
const Evoral::Beats length_beats = Evoral::Beats::ticks_at_rate(t, source->ppqn());
BeatsFramesConverter converter(smfs->session().tempo_map(), pos);
smfs->update_length(pos + converter.to(length_beats.round_up_to_beat()));
smfs->mark_streaming_write_completed (source_lock);

View file

@ -194,8 +194,7 @@ InternalSend::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame
/* target gain has changed */
Amp::apply_gain (mixbufs, nframes, _current_gain, tgain);
_current_gain = tgain;
_current_gain = Amp::apply_gain (mixbufs, _session.nominal_frame_rate(), nframes, _current_gain, tgain);
} else if (tgain == 0.0) {

View file

@ -21,6 +21,7 @@
#include <cstdio>
#include "ardour/interpolation.h"
#include "ardour/midi_buffer.h"
using namespace ARDOUR;
@ -47,7 +48,7 @@ LinearInterpolation::interpolate (int channel, framecnt_t nframes, Sample *input
}
if (input && output) {
// Linearly interpolate into the output buffer
// Linearly interpolate into the output buffer
output[outsample] =
input[i] * (1.0f - fractional_phase_part) +
input[i+1] * fractional_phase_part;
@ -63,90 +64,127 @@ LinearInterpolation::interpolate (int channel, framecnt_t nframes, Sample *input
framecnt_t
CubicInterpolation::interpolate (int channel, framecnt_t nframes, Sample *input, Sample *output)
{
// index in the input buffers
framecnt_t i = 0;
// index in the input buffers
framecnt_t i = 0;
double acceleration;
double distance = 0.0;
double acceleration;
double distance = 0.0;
if (_speed != _target_speed) {
acceleration = _target_speed - _speed;
} else {
acceleration = 0.0;
}
if (_speed != _target_speed) {
acceleration = _target_speed - _speed;
} else {
acceleration = 0.0;
}
distance = phase[channel];
distance = phase[channel];
if (nframes < 3) {
/* no interpolation possible */
if (nframes < 3) {
/* no interpolation possible */
for (i = 0; i < nframes; ++i) {
output[i] = input[i];
}
if (input && output) {
for (i = 0; i < nframes; ++i) {
output[i] = input[i];
}
}
return nframes;
}
return nframes;
}
/* keep this condition out of the inner loop */
/* keep this condition out of the inner loop */
if (input && output) {
if (input && output) {
Sample inm1;
Sample inm1;
if (floor (distance) == 0.0) {
/* best guess for the fake point we have to add to be able to interpolate at i == 0:
.... maintain slope of first actual segment ...
*/
inm1 = input[i] - (input[i+1] - input[i]);
} else {
inm1 = input[i-1];
}
if (floor (distance) == 0.0) {
/* best guess for the fake point we have to add to be able to interpolate at i == 0:
.... maintain slope of first actual segment ...
*/
inm1 = input[i] - (input[i+1] - input[i]);
} else {
inm1 = input[i-1];
}
for (framecnt_t outsample = 0; outsample < nframes; ++outsample) {
for (framecnt_t outsample = 0; outsample < nframes; ++outsample) {
float f = floor (distance);
float fractional_phase_part = distance - f;
float f = floor (distance);
float fractional_phase_part = distance - f;
/* get the index into the input we should start with */
/* get the index into the input we should start with */
i = lrintf (f);
i = lrintf (f);
/* fractional_phase_part only reaches 1.0 thanks to float imprecision. In theory
it should always be < 1.0. If it ever >= 1.0, then bump the index we use
and back it off. This is the point where we "skip" an entire sample in the
input, because the phase part has accumulated so much error that we should
really be closer to the next sample. or something like that ...
*/
/* fractional_phase_part only reaches 1.0 thanks to float imprecision. In theory
it should always be < 1.0. If it ever >= 1.0, then bump the index we use
and back it off. This is the point where we "skip" an entire sample in the
input, because the phase part has accumulated so much error that we should
really be closer to the next sample. or something like that ...
*/
if (fractional_phase_part >= 1.0) {
fractional_phase_part -= 1.0;
++i;
}
if (fractional_phase_part >= 1.0) {
fractional_phase_part -= 1.0;
++i;
}
// Cubically interpolate into the output buffer: keep this inlined for speed and rely on compiler
// optimization to take care of the rest
// shamelessly ripped from Steve Harris' swh-plugins (ladspa-util.h)
// Cubically interpolate into the output buffer: keep this inlined for speed and rely on compiler
// optimization to take care of the rest
// shamelessly ripped from Steve Harris' swh-plugins (ladspa-util.h)
output[outsample] = input[i] + 0.5f * fractional_phase_part * (input[i+1] - inm1 +
fractional_phase_part * (4.0f * input[i+1] + 2.0f * inm1 - 5.0f * input[i] - input[i+2] +
fractional_phase_part * (3.0f * (input[i] - input[i+1]) - inm1 + input[i+2])));
output[outsample] = input[i] + 0.5f * fractional_phase_part * (input[i+1] - inm1 +
fractional_phase_part * (4.0f * input[i+1] + 2.0f * inm1 - 5.0f * input[i] - input[i+2] +
fractional_phase_part * (3.0f * (input[i] - input[i+1]) - inm1 + input[i+2])));
distance += _speed + acceleration;
inm1 = input[i];
}
distance += _speed + acceleration;
inm1 = input[i];
}
i = floor(distance);
phase[channel] = distance - floor(distance);
i = floor(distance);
phase[channel] = distance - floor(distance);
} else {
/* used to calculate play-distance with acceleration (silent roll)
* (use same algorithm as real playback for identical rounding/floor'ing)
*/
for (framecnt_t outsample = 0; outsample < nframes; ++outsample) {
distance += _speed + acceleration;
}
i = floor(distance);
}
} else {
/* used to calculate play-distance with acceleration (silent roll)
* (use same algorithm as real playback for identical rounding/floor'ing)
*/
for (framecnt_t outsample = 0; outsample < nframes; ++outsample) {
distance += _speed + acceleration;
}
i = floor(distance);
}
return i;
return i;
}
framecnt_t
CubicMidiInterpolation::distance (framecnt_t nframes, bool roll)
{
assert(phase.size() == 1);
framecnt_t i = 0;
double acceleration;
double distance = 0.0;
if (nframes < 3) {
return nframes;
}
if (_speed != _target_speed) {
acceleration = _target_speed - _speed;
} else {
acceleration = 0.0;
}
distance = phase[0];
for (framecnt_t outsample = 0; outsample < nframes; ++outsample) {
distance += _speed + acceleration;
}
if (roll) {
phase[0] = distance - floor(distance);
}
i = floor(distance);
return i;
}

View file

@ -527,7 +527,7 @@ IO::state (bool /*full_state*/)
string str;
vector<string>::iterator ci;
int n;
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
Glib::Threads::Mutex::Lock lm (io_lock);
node->add_property("name", _name);
@ -588,7 +588,7 @@ IO::set_state (const XMLNode& node, int version)
const XMLProperty* prop;
XMLNodeConstIterator iter;
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
/* force use of non-localized representation of decimal point,
since we use it a lot in XML files and so forth.
@ -644,7 +644,7 @@ IO::set_state_2X (const XMLNode& node, int version, bool in)
{
const XMLProperty* prop;
XMLNodeConstIterator iter;
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
/* force use of non-localized representation of decimal point,
since we use it a lot in XML files and so forth.
@ -1040,7 +1040,8 @@ IO::make_connections_2X (const XMLNode& node, int /*version*/, bool in)
if (p != string::npos) {
ports[x].replace (p, 4, "/audio_out");
}
nth(i)->connect (ports[x]);
if (NULL != nth(i).get())
nth(i)->connect (ports[x]);
}
}
@ -1082,7 +1083,8 @@ IO::make_connections_2X (const XMLNode& node, int /*version*/, bool in)
if (p != string::npos) {
ports[x].replace (p, 3, "/audio_in");
}
nth(i)->connect (ports[x]);
if (NULL != nth(i).get())
nth(i)->connect (ports[x]);
}
}
@ -1174,7 +1176,6 @@ IO::parse_gain_string (const string& str, vector<string>& ports)
{
string::size_type pos, opos;
pos = 0;
opos = 0;
ports.clear ();
@ -1606,8 +1607,10 @@ IO::connected_to (boost::shared_ptr<const IO> other) const
for (i = 0; i < no; ++i) {
for (j = 0; j < ni; ++j) {
if (nth(i)->connected_to (other->nth(j)->name())) {
return true;
if ((NULL != nth(i).get()) && (NULL != other->nth(j).get())) {
if (nth(i)->connected_to (other->nth(j)->name())) {
return true;
}
}
}
}

View file

@ -351,7 +351,7 @@ LadspaPlugin::add_state (XMLNode* root) const
{
XMLNode *child;
char buf[16];
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
for (uint32_t i = 0; i < parameter_count(); ++i){
@ -384,7 +384,7 @@ LadspaPlugin::set_state (const XMLNode& node, int version)
const char *data;
uint32_t port_id;
#endif
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
if (node.name() != state_node_name()) {
error << _("Bad node sent to LadspaPlugin::set_state") << endmsg;
@ -434,7 +434,7 @@ LadspaPlugin::set_state_2X (const XMLNode& node, int /* version */)
const char *data;
uint32_t port_id;
#endif
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
if (node.name() != state_node_name()) {
error << _("Bad node sent to LadspaPlugin::set_state") << endmsg;

View file

@ -31,7 +31,7 @@ Legatize::~Legatize ()
Command*
Legatize::operator()(boost::shared_ptr<ARDOUR::MidiModel> model,
Evoral::MusicalTime position,
Evoral::Beats position,
std::vector<Legatize::Notes>& seqs)
{
MidiModel::NoteDiffCommand* cmd = new MidiModel::NoteDiffCommand(model, "legatize");
@ -43,10 +43,10 @@ Legatize::operator()(boost::shared_ptr<ARDOUR::MidiModel> model,
break;
}
const Evoral::MusicalTime new_end = (*next)->time() - Evoral::MusicalTime::tick();
const Evoral::Beats new_end = (*next)->time() - Evoral::Beats::tick();
if ((*i)->end_time() > new_end ||
(!_shrink_only && (*i)->end_time() < new_end)) {
const Evoral::MusicalTime new_length(new_end - (*i)->time());
const Evoral::Beats new_length(new_end - (*i)->time());
cmd->change((*i), MidiModel::NoteDiffCommand::Length, new_length);
}

View file

@ -220,7 +220,7 @@ Location::set_start (framepos_t s, bool force, bool allow_bbt_recompute)
assert (_end >= 0);
return 0;
} else {
} else if (!force) {
/* range locations must exceed a minimum duration */
if (_end - s < Config->get_range_location_minimum()) {
return -1;
@ -251,7 +251,7 @@ Location::set_start (framepos_t s, bool force, bool allow_bbt_recompute)
/** Set end position.
* @param s New end.
* @param force true to force setting, even if the given new start is after the current end.
* @param force true to force setting, even if the given new end is before the current start.
* @param allow_bbt_recompute True to recompute BBT end time from the new given end time.
*/
int
@ -288,7 +288,7 @@ Location::set_end (framepos_t e, bool force, bool allow_bbt_recompute)
assert (_end >= 0);
return 0;
} else {
} else if (!force) {
/* range locations must exceed a minimum duration */
if (e - _start < Config->get_range_location_minimum()) {
return -1;
@ -1113,6 +1113,30 @@ Locations::set_state (const XMLNode& node, int version)
}
}
/* We may have some unused locations in the old list. */
for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
LocationList::iterator tmp = i;
++tmp;
LocationList::iterator n = new_locations.begin();
bool found = false;
while (n != new_locations.end ()) {
if ((*i)->id() == (*n)->id()) {
found = true;
break;
}
++n;
}
if (!found) {
delete *i;
locations.erase (i);
}
i = tmp;
}
locations = new_locations;
if (locations.size()) {

View file

@ -52,6 +52,7 @@ LTC_Slave::LTC_Slave (Session& s)
delayedlocked = 10;
monotonic_cnt = 0;
fps_detected=false;
sync_lock_broken = false;
ltc_timecode = session.config.get_timecode_format();
a3e_timecode = session.config.get_timecode_format();
@ -124,6 +125,7 @@ LTC_Slave::resync_xrun()
{
DEBUG_TRACE (DEBUG::LTC, "LTC resync_xrun()\n");
engine_dll_initstate = 0;
sync_lock_broken = false;
}
void
@ -131,6 +133,7 @@ LTC_Slave::resync_latency()
{
DEBUG_TRACE (DEBUG::LTC, "LTC resync_latency()\n");
engine_dll_initstate = 0;
sync_lock_broken = false;
if (!session.deletion_in_progress() && session.ltc_output_io()) { /* check if Port exits */
boost::shared_ptr<Port> ltcport = session.ltc_input_port();
@ -147,6 +150,7 @@ LTC_Slave::reset()
transport_direction = 0;
ltc_speed = 0;
engine_dll_initstate = 0;
sync_lock_broken = false;
}
void
@ -381,6 +385,8 @@ LTC_Slave::process_ltc(framepos_t const /*now*/)
timecode_negative_offset, timecode_offset
);
ltc_frame += ltc_slave_latency.max + session.worst_playback_latency();
framepos_t cur_timestamp = frame.off_end + 1;
DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC F: %1 LF: %2 N: %3 L: %4\n", ltc_frame, last_ltc_frame, cur_timestamp, last_timestamp));
if (frame.off_end + 1 <= last_timestamp || last_timestamp == 0) {
@ -436,7 +442,7 @@ LTC_Slave::speed_and_position (double& speed, framepos_t& pos)
if (last_timestamp == 0) {
engine_dll_initstate = 0;
delayedlocked++;
if (delayedlocked < 10) ++delayedlocked;
}
else if (engine_dll_initstate != transport_direction && ltc_speed != 0) {
engine_dll_initstate = transport_direction;
@ -463,7 +469,7 @@ LTC_Slave::speed_and_position (double& speed, framepos_t& pos)
reset();
}
parse_ltc(nframes, in, now - ltc_slave_latency.max );
parse_ltc(nframes, in, now);
process_ltc(now);
}
@ -473,7 +479,8 @@ LTC_Slave::speed_and_position (double& speed, framepos_t& pos)
pos = session.transport_frame();
return true;
} else if (ltc_speed != 0) {
delayedlocked = 0;
if (delayedlocked > 1) delayedlocked--;
else if (current_delta == 0) delayedlocked = 0;
}
if (abs(now - last_timestamp) > FLYWHEEL_TIMEOUT) {
@ -549,6 +556,11 @@ LTC_Slave::speed_and_position (double& speed, framepos_t& pos)
speed = 1.0;
}
if (speed != 0 && delayedlocked == 0 && fabsf(speed) != 1.0) {
sync_lock_broken = true;
DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC speed not locked %1 %2\n", speed, ltc_speed));
}
return true;
}
@ -590,7 +602,8 @@ LTC_Slave::approximate_current_delta() const
} else if ((monotonic_cnt - last_timestamp) > 2 * frames_per_ltc_frame) {
snprintf(delta, sizeof(delta), "%s", _("flywheel"));
} else {
snprintf(delta, sizeof(delta), "\u0394<span foreground=\"green\" face=\"monospace\" >%s%s%lld</span>sm",
snprintf(delta, sizeof(delta), "\u0394<span foreground=\"%s\" face=\"monospace\" >%s%s%lld</span>sm",
sync_lock_broken ? "red" : "green",
LEADINGZERO(llabs(current_delta)), PLUSMINUS(-current_delta), llabs(current_delta));
}
return std::string(delta);

View file

@ -914,7 +914,7 @@ LV2Plugin::add_state(XMLNode* root) const
XMLNode* child;
char buf[16];
LocaleGuard lg(X_("POSIX"));
LocaleGuard lg(X_("C"));
for (uint32_t i = 0; i < parameter_count(); ++i) {
if (parameter_is_input(i) && parameter_is_control(i)) {
@ -1074,11 +1074,13 @@ ARDOUR::lv2plugin_get_port_value(const char* port_symbol,
std::string
LV2Plugin::do_save_preset(string name)
{
LilvNode* plug_name = lilv_plugin_get_name(_impl->plugin);
const string prefix = legalize_for_uri(lilv_node_as_string(plug_name));
const string base_name = legalize_for_uri(name);
const string file_name = base_name + ".ttl";
const string bundle = Glib::build_filename(
Glib::get_home_dir(),
Glib::build_filename(".lv2", base_name + ".lv2"));
Glib::build_filename(".lv2", prefix + "_" + base_name + ".lv2"));
LilvState* state = lilv_state_new_from_instance(
_impl->plugin,
@ -1110,7 +1112,7 @@ LV2Plugin::do_save_preset(string name)
std::string uri = Glib::filename_to_uri(Glib::build_filename(bundle, file_name));
LilvNode *node_bundle = lilv_new_uri(_world.world, Glib::filename_to_uri(Glib::build_filename(bundle, "/")).c_str());
LilvNode *node_preset = lilv_new_uri(_world.world, uri.c_str());
#ifdef HAVE_LILV_0_19_2
#ifdef HAVE_LILV_0_21_3
lilv_world_unload_resource(_world.world, node_preset);
lilv_world_unload_bundle(_world.world, node_bundle);
#endif
@ -1118,20 +1120,41 @@ LV2Plugin::do_save_preset(string name)
lilv_world_load_resource(_world.world, node_preset);
lilv_node_free(node_bundle);
lilv_node_free(node_preset);
lilv_node_free(plug_name);
return uri;
}
void
LV2Plugin::do_remove_preset(string name)
{
string preset_file = Glib::build_filename(
Glib::get_home_dir(),
Glib::build_filename(
Glib::build_filename(".lv2", "presets"),
name + ".ttl"
)
);
::g_unlink(preset_file.c_str());
#ifdef HAVE_LILV_0_21_3
/* Look up preset record by label (FIXME: ick, label as ID) */
const PresetRecord* r = preset_by_label(name);
if (!r) {
return;
}
/* Load a LilvState for the preset. */
LilvWorld* world = _world.world;
LilvNode* pset = lilv_new_uri(world, r->uri.c_str());
LilvState* state = lilv_state_new_from_world(world, _uri_map.urid_map(), pset);
if (!state) {
lilv_node_free(pset);
return;
}
/* Delete it from the file system. This will remove the preset file and the entry
from the manifest. If this results in an empty manifest (i.e. the
preset is the only thing in the bundle), then the bundle is removed. */
lilv_state_delete(world, state);
lilv_state_free(state);
lilv_node_free(pset);
#endif
/* Without lilv_state_delete(), we could delete the preset file, but this
would leave a broken bundle/manifest around, so the preset would still
be visible, but broken. Naively deleting a bundle is too dangerous, so
we simply do not support preset deletion with older Lilv */
}
bool
@ -1529,7 +1552,7 @@ LV2Plugin::set_state(const XMLNode& node, int version)
const char* sym;
const char* value;
uint32_t port_id;
LocaleGuard lg(X_("POSIX"));
LocaleGuard lg(X_("C"));
if (node.name() != state_node_name()) {
error << _("Bad node sent to LV2Plugin::set_state") << endmsg;
@ -2012,7 +2035,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
LV2_Evbuf* buf = _ev_buffers[msg.index];
LV2_Evbuf_Iterator i = lv2_evbuf_end(buf);
const LV2_Atom* const atom = (const LV2_Atom*)&body[0];
if (!lv2_evbuf_write(&i, nframes, 0, atom->type, atom->size,
if (!lv2_evbuf_write(&i, nframes - 1, 0, atom->type, atom->size,
(const uint8_t*)(atom + 1))) {
error << "Failed to write data to LV2 event buffer\n";
}
@ -2287,8 +2310,6 @@ LV2World::LV2World()
: world(lilv_world_new())
, _bundle_checked(false)
{
lilv_world_load_all(world);
atom_AtomPort = lilv_new_uri(world, LV2_ATOM__AtomPort);
atom_Chunk = lilv_new_uri(world, LV2_ATOM__Chunk);
atom_Sequence = lilv_new_uri(world, LV2_ATOM__Sequence);
@ -2392,6 +2413,7 @@ LV2World::load_bundled_plugins(bool verbose)
lilv_node_free(node);
}
lilv_world_load_all(world);
_bundle_checked = true;
}
}

View file

@ -0,0 +1,143 @@
/*
Copyright (C) 2006-2015 Paul Davis
Author: David Robillard
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.
*/
#include "ardour/buffer_set.h"
#include "ardour/midi_buffer.h"
#include "ardour/midi_channel_filter.h"
#include "pbd/ffs.h"
namespace ARDOUR {
MidiChannelFilter::MidiChannelFilter()
: _mode_mask(0x0000FFFF)
{}
void
MidiChannelFilter::filter(BufferSet& bufs)
{
ChannelMode mode;
uint16_t mask;
get_mode_and_mask(&mode, &mask);
if (mode == AllChannels) {
return;
}
MidiBuffer& buf = bufs.get_midi(0);
for (MidiBuffer::iterator e = buf.begin(); e != buf.end(); ) {
Evoral::MIDIEvent<framepos_t> ev(*e, false);
if (ev.is_channel_event()) {
switch (mode) {
case FilterChannels:
if (0 == ((1 << ev.channel()) & mask)) {
e = buf.erase (e);
} else {
++e;
}
break;
case ForceChannel:
ev.set_channel(PBD::ffs(mask) - 1);
++e;
break;
case AllChannels:
/* handled by the opening if() */
++e;
break;
}
} else {
++e;
}
}
}
bool
MidiChannelFilter::filter(uint8_t* buf, uint32_t len)
{
ChannelMode mode;
uint16_t mask;
get_mode_and_mask(&mode, &mask);
const uint8_t type = buf[0] & 0xF0;
const bool is_channel_event = (0x80 <= type) && (type <= 0xE0);
if (!is_channel_event) {
return false;
}
const uint8_t channel = buf[0] & 0x0F;
switch (mode) {
case AllChannels:
return false;
case FilterChannels:
return !((1 << channel) & mask);
case ForceChannel:
buf[0] = (0xF0 & buf[0]) | (0x0F & (PBD::ffs(mask) - 1));
return false;
}
return false;
}
/** If mode is ForceChannel, force mask to the lowest set channel or 1 if no
* channels are set.
*/
static inline uint16_t
force_mask(const ChannelMode mode, const uint16_t mask)
{
return ((mode == ForceChannel)
? (mask ? (1 << (PBD::ffs(mask) - 1)) : 1)
: mask);
}
bool
MidiChannelFilter::set_channel_mode(ChannelMode mode, uint16_t mask)
{
ChannelMode old_mode;
uint16_t old_mask;
get_mode_and_mask(&old_mode, &old_mask);
if (old_mode != mode || old_mask != mask) {
mask = force_mask(mode, mask);
g_atomic_int_set(&_mode_mask, (uint32_t(mode) << 16) | uint32_t(mask));
ChannelModeChanged();
return true;
}
return false;
}
bool
MidiChannelFilter::set_channel_mask(uint16_t mask)
{
ChannelMode mode;
uint16_t old_mask;
get_mode_and_mask(&mode, &old_mask);
if (old_mask != mask) {
mask = force_mask(mode, mask);
g_atomic_int_set(&_mode_mask, (uint32_t(mode) << 16) | uint32_t(mask));
ChannelMaskChanged();
return true;
}
return false;
}
} /* namespace ARDOUR */

View file

@ -48,6 +48,7 @@
#include "ardour/midi_port.h"
#include "ardour/midi_region.h"
#include "ardour/midi_ring_buffer.h"
#include "ardour/midi_track.h"
#include "ardour/playlist_factory.h"
#include "ardour/region_factory.h"
#include "ardour/session.h"
@ -134,6 +135,7 @@ MidiDiskstream::init ()
_capture_buf = new MidiRingBuffer<framepos_t>(size);
_n_channels = ChanCount(DataType::MIDI, 1);
interpolation.add_channel_to (0,0);
}
MidiDiskstream::~MidiDiskstream ()
@ -401,11 +403,10 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
}
if (nominally_recording || rec_nframes) {
// Pump entire port buffer into the ring buffer (FIXME: split cycles?)
MidiBuffer& buf = sp->get_midi_buffer(nframes);
ChannelMode mode = AllChannels; // _track->get_capture_channel_mode ();
uint32_t mask = 0xffff; // _track->get_capture_channel_mask ();
// Pump entire port buffer into the ring buffer (TODO: split cycles?)
MidiBuffer& buf = sp->get_midi_buffer(nframes);
MidiTrack* mt = dynamic_cast<MidiTrack*>(_track);
MidiChannelFilter* filter = mt ? &mt->capture_filter() : NULL;
for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
Evoral::MIDIEvent<MidiBuffer::TimeType> ev(*i, false);
@ -439,31 +440,12 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
const framecnt_t loop_offset = _num_captured_loops * loop_length;
const framepos_t event_time = transport_frame + loop_offset - _accumulated_capture_offset + ev.time();
if (event_time < 0 || event_time < first_recordable_frame) {
/* Event out of range, skip */
continue;
}
switch (mode) {
case AllChannels:
_capture_buf->write(event_time,
ev.type(), ev.size(), ev.buffer());
break;
case FilterChannels:
if (ev.is_channel_event()) {
if ((1<<ev.channel()) & mask) {
_capture_buf->write(event_time,
ev.type(), ev.size(), ev.buffer());
}
} else {
_capture_buf->write(event_time,
ev.type(), ev.size(), ev.buffer());
}
break;
case ForceChannel:
if (ev.is_channel_event()) {
ev.set_channel (PBD::ffs(mask) - 1);
}
_capture_buf->write(event_time,
ev.type(), ev.size(), ev.buffer());
break;
if (!filter || !filter->filter(ev.buffer(), ev.size())) {
_capture_buf->write(event_time, ev.type(), ev.size(), ev.buffer());
}
}
g_atomic_int_add(const_cast<gint*>(&_frames_pending_write), nframes);
@ -515,24 +497,35 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
playback_distance = nframes;
} else if (_actual_speed != 1.0f && _target_speed > 0) {
interpolation.set_speed (_target_speed);
playback_distance = interpolation.distance (nframes);
} else {
/* XXX: should be doing varispeed stuff here, similar to the code in AudioDiskstream::process */
playback_distance = nframes;
}
if (need_disk_signal) {
/* copy the diskstream data to all output buffers */
MidiBuffer& mbuf (bufs.get_midi (0));
get_playback (mbuf, nframes);
get_playback (mbuf, playback_distance);
/* leave the audio count alone */
ChanCount cnt (DataType::MIDI, 1);
cnt.set (DataType::AUDIO, bufs.count().n_audio());
bufs.set_count (cnt);
/* vari-speed */
if (_target_speed > 0 && _actual_speed != 1.0f) {
MidiBuffer& mbuf (bufs.get_midi (0));
for (MidiBuffer::iterator i = mbuf.begin(); i != mbuf.end(); ++i) {
MidiBuffer::TimeType *tme = i.timeptr();
*tme = (*tme) * nframes / playback_distance;
}
}
}
return 0;
@ -543,7 +536,10 @@ MidiDiskstream::calculate_playback_distance (pframes_t nframes)
{
frameoffset_t playback_distance = nframes;
/* XXX: should be doing varispeed stuff once it's implemented in ::process() above */
if (!record_enabled() && _actual_speed != 1.0f && _actual_speed > 0.f) {
interpolation.set_speed (_target_speed);
playback_distance = interpolation.distance (nframes, false);
}
if (_actual_speed < 0.0) {
return -playback_distance;
@ -557,6 +553,10 @@ MidiDiskstream::commit (framecnt_t playback_distance)
{
bool need_butler = false;
if (!_io || !_io->active()) {
return false;
}
if (_actual_speed < 0.0) {
playback_sample -= playback_distance;
} else {
@ -584,10 +584,33 @@ MidiDiskstream::commit (framecnt_t playback_distance)
* need the butler is done correctly.
*/
/* furthermore..
*
* Doing heavy GUI operations[1] can stall also the butler.
* The RT-thread meanwhile will happily continue and
* frames_read (from buffer to output) will become larger
* than frames_written (from disk to buffer).
*
* The disk-stream is now behind..
*
* In those cases the butler needs to be summed to refill the buffer (done now)
* AND we need to skip (frames_read - frames_written). ie remove old events
* before playback_sample from the rinbuffer.
*
* [1] one way to do so is described at #6170.
* For me just popping up the context-menu on a MIDI-track header
* of a track with a large (think beethoven :) midi-region also did the
* trick. The playhead stalls for 2 or 3 sec, until the context-menu shows.
*
* In both cases the root cause is that redrawing MIDI regions on the GUI is still very slow
* and can stall
*/
if (frames_read <= frames_written) {
if ((frames_written - frames_read) + playback_distance < midi_readahead) {
need_butler = true;
}
} else {
need_butler = true;
}
@ -620,7 +643,7 @@ MidiDiskstream::overwrite_existing_buffers ()
having the old data or knowing what change caused the overwrite. */
midi_playlist()->resolve_note_trackers (*_playback_buf, overwrite_frame);
read (overwrite_frame, disk_io_chunk_frames, false);
read (overwrite_frame, disk_read_chunk_frames, false);
file_frame = overwrite_frame; // it was adjusted by ::read()
overwrite_queued = false;
_pending_overwrite = false;
@ -687,6 +710,9 @@ MidiDiskstream::read (framepos_t& start, framecnt_t dur, bool reversed)
framecnt_t loop_length = 0;
Location* loc = 0;
MidiTrack* mt = dynamic_cast<MidiTrack*>(_track);
MidiChannelFilter* filter = mt ? &mt->playback_filter() : NULL;
if (!reversed) {
loc = loop_location;
@ -723,7 +749,7 @@ MidiDiskstream::read (framepos_t& start, framecnt_t dur, bool reversed)
this_read = min(dur,this_read);
if (midi_playlist()->read (*_playback_buf, start, this_read) != this_read) {
if (midi_playlist()->read (*_playback_buf, start, this_read, 0, filter) != this_read) {
error << string_compose(
_("MidiDiskstream %1: cannot read %2 from playlist at frame %3"),
id(), this_read, start) << endmsg;
@ -790,16 +816,17 @@ MidiDiskstream::do_refill ()
uint32_t frames_read = g_atomic_int_get(&_frames_read_from_ringbuffer);
uint32_t frames_written = g_atomic_int_get(&_frames_written_to_ringbuffer);
if ((frames_written - frames_read) >= midi_readahead) {
if ((frames_read < frames_written) && (frames_written - frames_read) >= midi_readahead) {
return 0;
}
framecnt_t to_read = midi_readahead - (frames_written - frames_read);
framecnt_t to_read = midi_readahead - ((framecnt_t)frames_written - (framecnt_t)frames_read);
//cout << "MDS read for midi_readahead " << to_read << " rb_contains: "
// << frames_written - frames_read << endl;
to_read = (framecnt_t) min ((framecnt_t) to_read, (framecnt_t) (max_framepos - file_frame));
to_read = min (to_read, (framecnt_t) (max_framepos - file_frame));
to_read = min (to_read, (framecnt_t) write_space);
if (read (file_frame, to_read, reversed)) {
ret = -1;
@ -810,12 +837,12 @@ MidiDiskstream::do_refill ()
/** Flush pending data to disk.
*
* Important note: this function will write *AT MOST* disk_io_chunk_frames
* Important note: this function will write *AT MOST* disk_write_chunk_frames
* of data to disk. it will never write more than that. If it writes that
* much and there is more than that waiting to be written, it will return 1,
* otherwise 0 on success or -1 on failure.
*
* If there is less than disk_io_chunk_frames to be written, no data will be
* If there is less than disk_write_chunk_frames to be written, no data will be
* written at all unless @a force_flush is true.
*/
int
@ -832,7 +859,7 @@ MidiDiskstream::do_flush (RunContext /*context*/, bool force_flush)
if (total == 0 ||
_capture_buf->read_space() == 0 ||
(!force_flush && (total < disk_io_chunk_frames) && was_recording)) {
(!force_flush && (total < disk_write_chunk_frames) && was_recording)) {
goto out;
}
@ -847,7 +874,7 @@ MidiDiskstream::do_flush (RunContext /*context*/, bool force_flush)
let the caller know too.
*/
if (total >= 2 * disk_io_chunk_frames || ((force_flush || !was_recording) && total > disk_io_chunk_frames)) {
if (total >= 2 * disk_write_chunk_frames || ((force_flush || !was_recording) && total > disk_write_chunk_frames)) {
ret = 1;
}
@ -855,10 +882,10 @@ MidiDiskstream::do_flush (RunContext /*context*/, bool force_flush)
/* push out everything we have, right now */
to_write = max_framecnt;
} else {
to_write = disk_io_chunk_frames;
to_write = disk_write_chunk_frames;
}
if (record_enabled() && ((total > disk_io_chunk_frames) || force_flush)) {
if (record_enabled() && ((total > disk_write_chunk_frames) || force_flush)) {
Source::Lock lm(_write_source->mutex());
if (_write_source->midi_write (lm, *_capture_buf, get_capture_start_frame (0), to_write) != to_write) {
error << string_compose(_("MidiDiskstream %1: cannot write to disk"), id()) << endmsg;
@ -940,14 +967,14 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
/* set length in beats to entire capture length */
BeatsFramesConverter converter (_session.tempo_map(), capture_info.front()->start);
const Evoral::MusicalTime total_capture_beats = converter.from (total_capture);
const Evoral::Beats total_capture_beats = converter.from (total_capture);
_write_source->set_length_beats (total_capture_beats);
/* flush to disk: this step differs from the audio path,
where all the data is already on disk.
*/
_write_source->mark_midi_streaming_write_completed (source_lock, Evoral::Sequence<Evoral::MusicalTime>::ResolveStuckNotes, total_capture_beats);
_write_source->mark_midi_streaming_write_completed (source_lock, Evoral::Sequence<Evoral::Beats>::ResolveStuckNotes, total_capture_beats);
/* we will want to be able to keep (over)writing the source
but we don't want it to be removable. this also differs
@ -1165,7 +1192,7 @@ MidiDiskstream::get_state ()
{
XMLNode& node (Diskstream::get_state());
char buf[64];
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
if (_write_source && _session.get_record_enabled()) {
@ -1199,7 +1226,7 @@ MidiDiskstream::set_state (const XMLNode& node, int version)
XMLNodeList nlist = node.children();
XMLNodeIterator niter;
XMLNode* capture_pending_node = 0;
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
/* prevent write sources from being created */
@ -1409,6 +1436,8 @@ MidiDiskstream::get_playback (MidiBuffer& dst, framecnt_t nframes)
_playback_buf->resolve_tracker (dst, 0);
}
_playback_buf->skip_to (effective_start);
if (loc->end() >= effective_start && loc->end() < effective_start + nframes) {
/* end of loop is within the range we are reading, so
split the read in two, and lie about the location
@ -1440,6 +1469,7 @@ MidiDiskstream::get_playback (MidiBuffer& dst, framecnt_t nframes)
events_read = _playback_buf->read (dst, effective_start, effective_start + nframes);
}
} else {
_playback_buf->skip_to (playback_sample);
events_read = _playback_buf->read (dst, playback_sample, playback_sample + nframes);
}
@ -1501,6 +1531,19 @@ MidiDiskstream::reset_tracker ()
}
}
void
MidiDiskstream::resolve_tracker (Evoral::EventSink<framepos_t>& buffer, framepos_t time)
{
_playback_buf->resolve_tracker(buffer, time);
boost::shared_ptr<MidiPlaylist> mp (midi_playlist());
if (mp) {
mp->reset_note_trackers ();
}
}
boost::shared_ptr<MidiPlaylist>
MidiDiskstream::midi_playlist ()
{

View file

@ -620,7 +620,7 @@ MidiModel::NoteDiffCommand::unmarshal_change (XMLNode *xml_change)
if ((prop = xml_change->property ("old")) != 0) {
istringstream old_str (prop->value());
if (change.property == StartTime || change.property == Length) {
Evoral::MusicalTime old_time;
Evoral::Beats old_time;
old_str >> old_time;
change.old_value = old_time;
} else {
@ -636,7 +636,7 @@ MidiModel::NoteDiffCommand::unmarshal_change (XMLNode *xml_change)
if ((prop = xml_change->property ("new")) != 0) {
istringstream new_str (prop->value());
if (change.property == StartTime || change.property == Length) {
Evoral::MusicalTime new_time;
Evoral::Beats new_time;
new_str >> new_time;
change.new_value = Variant(new_time);
} else {
@ -1236,14 +1236,15 @@ MidiModel::PatchChangePtr
MidiModel::PatchChangeDiffCommand::unmarshal_patch_change (XMLNode* n)
{
XMLProperty* prop;
XMLProperty* prop_id;
Evoral::event_id_t id = 0;
Evoral::MusicalTime time = Evoral::MusicalTime();
Evoral::Beats time = Evoral::Beats();
int channel = 0;
int program = 0;
int bank = 0;
if ((prop = n->property ("id")) != 0) {
istringstream s (prop->value());
if ((prop_id = n->property ("id")) != 0) {
istringstream s (prop_id->value());
s >> id;
}
@ -1268,7 +1269,7 @@ MidiModel::PatchChangeDiffCommand::unmarshal_patch_change (XMLNode* n)
}
PatchChangePtr p (new Evoral::PatchChange<TimeType> (time, channel, program, bank));
assert(id);
assert(prop_id);
p->set_id (id);
return p;
}
@ -1476,8 +1477,8 @@ MidiModel::sync_to_source (const Glib::Threads::Mutex::Lock& source_lock)
bool
MidiModel::write_section_to (boost::shared_ptr<MidiSource> source,
const Glib::Threads::Mutex::Lock& source_lock,
Evoral::MusicalTime begin_time,
Evoral::MusicalTime end_time)
Evoral::Beats begin_time,
Evoral::Beats end_time)
{
ReadLock lock(read_lock());
MidiStateTracker mst;
@ -1489,12 +1490,12 @@ MidiModel::write_section_to (boost::shared_ptr<MidiSource> source,
source->mark_streaming_midi_write_started (source_lock, note_mode());
for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) {
const Evoral::Event<Evoral::MusicalTime>& ev (*i);
const Evoral::Event<Evoral::Beats>& ev (*i);
if (ev.time() >= begin_time && ev.time() < end_time) {
const Evoral::MIDIEvent<Evoral::MusicalTime>* mev =
static_cast<const Evoral::MIDIEvent<Evoral::MusicalTime>* > (&ev);
const Evoral::MIDIEvent<Evoral::Beats>* mev =
static_cast<const Evoral::MIDIEvent<Evoral::Beats>* > (&ev);
if (!mev) {
continue;
@ -1611,27 +1612,21 @@ MidiModel::find_sysex (gint sysex_id)
MidiModel::WriteLock
MidiModel::edit_lock()
{
boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
assert (ms);
boost::shared_ptr<MidiSource> ms = _midi_source.lock();
Glib::Threads::Mutex::Lock* source_lock = 0;
if (ms) {
/* Take source lock and invalidate iterator to release its lock on model.
Add currently active notes to _active_notes so we can restore them
if playback resumes at the same point after the edit. */
source_lock = new Glib::Threads::Mutex::Lock(ms->mutex());
ms->invalidate(*source_lock,
ms->session().transport_rolling() ? &_active_notes : NULL);
}
Glib::Threads::Mutex::Lock* source_lock = new Glib::Threads::Mutex::Lock (ms->mutex());
ms->invalidate(*source_lock); // Release cached iterator's read lock on model
return WriteLock(new WriteLockImpl(source_lock, _lock, _control_lock));
}
/** Lock just the model, the source lock must already be held.
* This should only be called from libardour/evoral places
*/
MidiModel::WriteLock
MidiModel::write_lock()
{
boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
assert (ms);
assert (!ms->mutex().trylock ());
return WriteLock(new WriteLockImpl(0, _lock, _control_lock));
}
int
MidiModel::resolve_overlaps_unlocked (const NotePtr note, void* arg)
{
@ -2026,7 +2021,7 @@ MidiModel::transpose (TimeType from, TimeType to, int semitones)
void
MidiModel::control_list_marked_dirty ()
{
AutomatableSequence<Evoral::MusicalTime>::control_list_marked_dirty ();
AutomatableSequence<Evoral::Beats>::control_list_marked_dirty ();
ContentsChanged (); /* EMIT SIGNAL */
}

View file

@ -17,21 +17,22 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <cassert>
#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <iostream>
#include <utility>
#include <stdlib.h>
#include "evoral/EventList.hpp"
#include "ardour/beats_frames_converter.h"
#include "ardour/debug.h"
#include "ardour/midi_model.h"
#include "ardour/midi_playlist.h"
#include "ardour/midi_region.h"
#include "ardour/midi_source.h"
#include "ardour/midi_state_tracker.h"
#include "ardour/session.h"
#include "ardour/types.h"
#include "i18n.h"
@ -43,6 +44,7 @@ using namespace std;
MidiPlaylist::MidiPlaylist (Session& session, const XMLNode& node, bool hidden)
: Playlist (session, node, DataType::MIDI, hidden)
, _note_mode(Sustained)
, _read_end(0)
{
#ifndef NDEBUG
const XMLProperty* prop = node.property("type");
@ -61,20 +63,26 @@ MidiPlaylist::MidiPlaylist (Session& session, const XMLNode& node, bool hidden)
MidiPlaylist::MidiPlaylist (Session& session, string name, bool hidden)
: Playlist (session, name, DataType::MIDI, hidden)
, _note_mode(Sustained)
, _read_end(0)
{
}
MidiPlaylist::MidiPlaylist (boost::shared_ptr<const MidiPlaylist> other, string name, bool hidden)
: Playlist (other, name, hidden)
, _note_mode(other->_note_mode)
, _read_end(0)
{
}
MidiPlaylist::MidiPlaylist (boost::shared_ptr<const MidiPlaylist> other, framepos_t start, framecnt_t dur, string name, bool hidden)
MidiPlaylist::MidiPlaylist (boost::shared_ptr<const MidiPlaylist> other,
framepos_t start,
framecnt_t dur,
string name,
bool hidden)
: Playlist (other, start, dur, name, hidden)
, _note_mode(other->_note_mode)
, _read_end(0)
{
/* this constructor does NOT notify others (session) */
}
MidiPlaylist::~MidiPlaylist ()
@ -97,204 +105,164 @@ struct EventsSortByTimeAndType {
}
};
/** Returns the number of frames in time duration read (eg could be large when 0 events are read) */
framecnt_t
MidiPlaylist::read (Evoral::EventSink<framepos_t>& dst, framepos_t start, framecnt_t dur, unsigned chan_n)
MidiPlaylist::read (Evoral::EventSink<framepos_t>& dst,
framepos_t start,
framecnt_t dur,
unsigned chan_n,
MidiChannelFilter* filter)
{
/* this function is never called from a realtime thread, so
its OK to block (for short intervals).
*/
typedef pair<MidiStateTracker*,framepos_t> TrackerInfo;
Playlist::RegionReadLock rl (this);
DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("++++++ %1 .. %2 +++++++ %3 trackers +++++++++++++++++\n",
start, start + dur, _note_trackers.size()));
DEBUG_TRACE (DEBUG::MidiPlaylistIO,
string_compose ("---- MidiPlaylist::read %1 .. %2 (%3 trackers) ----\n",
start, start + dur, _note_trackers.size()));
framepos_t end = start + dur - 1;
// relevent regions overlapping start <--> end
vector< boost::shared_ptr<Region> > regs;
vector< boost::shared_ptr<Region> > ended;
typedef pair<MidiStateTracker*,framepos_t> TrackerInfo;
vector<TrackerInfo> tracker_info;
NoteTrackers::iterator t;
/* First, emit any queued edit fixup events at start. */
for (NoteTrackers::iterator t = _note_trackers.begin(); t != _note_trackers.end(); ++t) {
t->second->fixer.emit(dst, _read_end, t->second->tracker);
}
/* Find relevant regions that overlap [start..end] */
const framepos_t end = start + dur - 1;
std::vector< boost::shared_ptr<Region> > regs;
std::vector< boost::shared_ptr<Region> > ended;
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
/* in this call to coverage, the return value indicates the
* overlap status of the read range (start...end) WRT to
* the region.
*/
switch ((*i)->coverage (start, end)) {
case Evoral::OverlapStart:
case Evoral::OverlapInternal:
case Evoral::OverlapExternal:
regs.push_back (*i);
break;
case Evoral::OverlapExternal:
/* this region is entirely contained in the read range */
regs.push_back (*i);
ended.push_back (*i);
break;
case Evoral::OverlapEnd:
/* this region ends within the read range */
regs.push_back (*i);
ended.push_back (*i);
break;
default:
/* we don't care */
break;
}
}
if (regs.size() == 1 &&
(ended.empty() || (ended.size() == 1 && ended.front() == regs.front()))) {
/* If we are reading from a single region, we can read directly into dst. Otherwise,
we read into a temporarily list, sort it, then write that to dst. */
const bool direct_read = regs.size() == 1 &&
(ended.empty() || (ended.size() == 1 && ended.front() == regs.front()));
/* just a single region - read directly into dst */
Evoral::EventList<framepos_t> evlist;
Evoral::EventSink<framepos_t>& tgt = direct_read ? dst : evlist;
DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("Single region (%1) read, ended during this read %2\n", regs.front()->name(),
ended.size()));
DEBUG_TRACE (DEBUG::MidiPlaylistIO,
string_compose ("\t%1 regions to read, direct: %2\n", regs.size(), direct_read));
boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(regs.front());
if (mr) {
NoteTrackers::iterator t = _note_trackers.find (mr.get());
MidiStateTracker* tracker;
bool new_tracker = false;
if (t == _note_trackers.end()) {
tracker = new MidiStateTracker;
new_tracker = true;
DEBUG_TRACE (DEBUG::MidiPlaylistIO, "\tBEFORE: new tracker\n");
} else {
tracker = t->second;
DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("\tBEFORE: tracker says there are %1 on notes\n", tracker->on()));
}
mr->read_at (dst, start, dur, chan_n, _note_mode, tracker);
DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("\tAFTER: tracker says there are %1 on notes\n", tracker->on()));
if (!ended.empty()) {
DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("\t%1 ended in this read, resolve notes and delete (%2) tracker\n",
mr->name(), ((new_tracker) ? "new" : "old")));
tracker->resolve_notes (dst, mr->last_frame());
delete tracker;
if (!new_tracker) {
_note_trackers.erase (t);
}
} else {
if (new_tracker) {
pair<Region*,MidiStateTracker*> newpair;
newpair.first = mr.get();
newpair.second = tracker;
_note_trackers.insert (newpair);
DEBUG_TRACE (DEBUG::MidiPlaylistIO, "\tadded tracker to trackers\n");
}
}
for (vector<boost::shared_ptr<Region> >::iterator i = regs.begin(); i != regs.end(); ++i) {
boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(*i);
if (!mr) {
continue;
}
} else {
/* multiple regions and/or note resolution: sort by layer, read into a temporary non-monotonically
sorted EventSink, sort and then insert into dst.
*/
DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("%1 regions to read, plus %2 trackers\n", regs.size(), tracker_info.size()));
Evoral::EventList<framepos_t> evlist;
DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("for %1 .. %2 we have %3 to consider\n", start, start+dur-1, regs.size()));
for (vector<boost::shared_ptr<Region> >::iterator i = regs.begin(); i != regs.end(); ++i) {
boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(*i);
if (!mr) {
continue;
}
NoteTrackers::iterator t = _note_trackers.find (mr.get());
MidiStateTracker* tracker;
bool new_tracker = false;
DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("Before %1 (%2 .. %3) we now have %4 events\n", mr->name(), mr->position(), mr->last_frame(), evlist.size()));
if (t == _note_trackers.end()) {
tracker = new MidiStateTracker;
new_tracker = true;
DEBUG_TRACE (DEBUG::MidiPlaylistIO, "\tBEFORE: new tracker\n");
} else {
tracker = t->second;
DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("\tBEFORE: tracker says there are %1 on notes\n", tracker->on()));
}
mr->read_at (evlist, start, dur, chan_n, _note_mode, tracker);
#ifndef NDEBUG
DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("After %1 (%2 .. %3) we now have %4\n", mr->name(), mr->position(), mr->last_frame(), evlist.size()));
for (Evoral::EventList<framepos_t>::iterator x = evlist.begin(); x != evlist.end(); ++x) {
DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("\t%1\n", **x));
}
DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("\tAFTER: tracker says there are %1 on notes\n", tracker->on()));
#endif
if (find (ended.begin(), ended.end(), *i) != ended.end()) {
/* the region ended within the read range, so
* resolve any dangling notes (i.e. notes whose
* end is beyond the end of the region).
*/
DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("\t%1 ended in this read, resolve notes and delete (%2) tracker\n",
mr->name(), ((new_tracker) ? "new" : "old")));
tracker->resolve_notes (evlist, (*i)->last_frame());
delete tracker;
if (!new_tracker) {
_note_trackers.erase (t);
}
} else {
if (new_tracker) {
_note_trackers.insert (make_pair (mr.get(), tracker));
DEBUG_TRACE (DEBUG::MidiPlaylistIO, "\tadded tracker to trackers\n");
}
}
/* Get the existing note tracker for this region, or create a new one. */
NoteTrackers::iterator t = _note_trackers.find (mr.get());
bool new_tracker = false;
boost::shared_ptr<RegionTracker> tracker;
if (t == _note_trackers.end()) {
tracker = boost::shared_ptr<RegionTracker>(new RegionTracker);
new_tracker = true;
DEBUG_TRACE (DEBUG::MidiPlaylistIO,
string_compose ("\tPre-read %1 (%2 .. %3): new tracker\n",
mr->name(), mr->position(), mr->last_frame()));
} else {
tracker = t->second;
DEBUG_TRACE (DEBUG::MidiPlaylistIO,
string_compose ("\tPre-read %1 (%2 .. %3): %4 active notes\n",
mr->name(), mr->position(), mr->last_frame(), tracker->tracker.on()));
}
if (!evlist.empty()) {
/* Read from region into target. */
mr->read_at (tgt, start, dur, chan_n, _note_mode, &tracker->tracker, filter);
DEBUG_TRACE (DEBUG::MidiPlaylistIO,
string_compose ("\tPost-read: %1 active notes\n", tracker->tracker.on()));
/* sort the event list */
EventsSortByTimeAndType<framepos_t> cmp;
evlist.sort (cmp);
if (find (ended.begin(), ended.end(), *i) != ended.end()) {
/* Region ended within the read range, so resolve any active notes
(either stuck notes in the data, or notes that end after the end
of the region). */
DEBUG_TRACE (DEBUG::MidiPlaylistIO,
string_compose ("\t%1 ended, resolve notes and delete (%2) tracker\n",
mr->name(), ((new_tracker) ? "new" : "old")));
#ifndef NDEBUG
DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("Final we now have %1 events\n", evlist.size()));
for (Evoral::EventList<framepos_t>::iterator x = evlist.begin(); x != evlist.end(); ++x) {
DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("\t%1\n", **x));
}
#endif
/* write into dst */
for (Evoral::EventList<framepos_t>::iterator e = evlist.begin(); e != evlist.end(); ++e) {
Evoral::Event<framepos_t>* ev (*e);
dst.write (ev->time(), ev->event_type(), ev->size(), ev->buffer());
delete ev;
tracker->tracker.resolve_notes (tgt, (*i)->last_frame());
if (!new_tracker) {
_note_trackers.erase (t);
}
} else {
if (new_tracker) {
_note_trackers.insert (make_pair (mr.get(), tracker));
DEBUG_TRACE (DEBUG::MidiPlaylistIO, "\tadded tracker to trackers\n");
}
}
}
DEBUG_TRACE (DEBUG::MidiPlaylistIO, "-------------------------------------------------------------\n");
if (!direct_read && !evlist.empty()) {
/* We've read from multiple regions, sort the event list by time. */
EventsSortByTimeAndType<framepos_t> cmp;
evlist.sort (cmp);
/* Copy ordered events from event list to dst. */
for (Evoral::EventList<framepos_t>::iterator e = evlist.begin(); e != evlist.end(); ++e) {
Evoral::Event<framepos_t>* ev (*e);
dst.write (ev->time(), ev->event_type(), ev->size(), ev->buffer());
delete ev;
}
}
DEBUG_TRACE (DEBUG::MidiPlaylistIO, "---- End MidiPlaylist::read ----\n");
_read_end = start + dur;
return dur;
}
void
MidiPlaylist::region_edited(boost::shared_ptr<Region> region,
const MidiModel::NoteDiffCommand* cmd)
{
typedef MidiModel::NoteDiffCommand Command;
boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(region);
if (!mr || !_session.transport_rolling()) {
return;
}
/* Take write lock to prevent concurrency with read(). */
Playlist::RegionWriteLock lock(this);
NoteTrackers::iterator t = _note_trackers.find(mr.get());
if (t == _note_trackers.end()) {
return; /* Region is not currently active, nothing to do. */
}
/* Queue any necessary edit compensation events. */
t->second->fixer.prepare(
_session.tempo_map(), cmd, mr->position() - mr->start(),
_read_end, mr->midi_source()->model()->active_notes());
}
void
MidiPlaylist::reset_note_trackers ()
{
Playlist::RegionWriteLock rl (this, false);
for (NoteTrackers::iterator n = _note_trackers.begin(); n != _note_trackers.end(); ++n) {
delete n->second;
}
DEBUG_TRACE (DEBUG::MidiTrackers, string_compose ("%1 reset all note trackers\n", name()));
_note_trackers.clear ();
}
@ -305,8 +273,7 @@ MidiPlaylist::resolve_note_trackers (Evoral::EventSink<framepos_t>& dst, framepo
Playlist::RegionWriteLock rl (this, false);
for (NoteTrackers::iterator n = _note_trackers.begin(); n != _note_trackers.end(); ++n) {
n->second->resolve_notes(dst, time);
delete n->second;
n->second->tracker.resolve_notes(dst, time);
}
DEBUG_TRACE (DEBUG::MidiTrackers, string_compose ("%1 resolve all note trackers\n", name()));
_note_trackers.clear ();
@ -316,14 +283,7 @@ void
MidiPlaylist::remove_dependents (boost::shared_ptr<Region> region)
{
/* MIDI regions have no dependents (crossfades) but we might be tracking notes */
NoteTrackers::iterator t = _note_trackers.find (region.get());
/* GACK! THREAD SAFETY! */
if (t != _note_trackers.end()) {
delete t->second;
_note_trackers.erase (t);
}
_note_trackers.erase(region.get());
}
int
@ -423,24 +383,3 @@ MidiPlaylist::contained_automation()
return ret;
}
bool
MidiPlaylist::region_changed (const PBD::PropertyChange& what_changed, boost::shared_ptr<Region> region)
{
if (in_flush || in_set_state) {
return false;
}
PBD::PropertyChange our_interests;
our_interests.add (Properties::midi_data);
bool parent_wants_notify = Playlist::region_changed (what_changed, region);
if (parent_wants_notify || what_changed.contains (our_interests)) {
notify_contents_changed ();
}
return true;
}

View file

@ -126,7 +126,8 @@ MidiPlaylistSource::read_unlocked (const Lock& lock,
Evoral::EventSink<framepos_t>& dst,
framepos_t /*position*/,
framepos_t start, framecnt_t cnt,
MidiStateTracker*) const
MidiStateTracker*,
MidiChannelFilter*) const
{
boost::shared_ptr<MidiPlaylist> mp = boost::dynamic_pointer_cast<MidiPlaylist> (_playlist);
@ -149,7 +150,7 @@ MidiPlaylistSource::write_unlocked (const Lock&,
}
void
MidiPlaylistSource::append_event_beats(const Glib::Threads::Mutex::Lock& /*lock*/, const Evoral::Event<Evoral::MusicalTime>& /*ev*/)
MidiPlaylistSource::append_event_beats(const Glib::Threads::Mutex::Lock& /*lock*/, const Evoral::Event<Evoral::Beats>& /*ev*/)
{
fatal << string_compose (_("programming error: %1"), "MidiPlaylistSource::append_event_beats() called - should be impossible") << endmsg;
abort(); /*NOTREACHED*/

View file

@ -40,6 +40,7 @@ MidiPort::MidiPort (const std::string& name, PortFlags flags)
, _resolve_required (false)
, _input_active (true)
, _always_parse (false)
, _trace_on (false)
{
_buffer = new MidiBuffer (AudioEngine::instance()->raw_buffer_size (DataType::MIDI));
}
@ -62,7 +63,7 @@ MidiPort::cycle_start (pframes_t nframes)
port_engine.midi_clear (port_engine.get_buffer (_port_handle, nframes));
}
if (_always_parse) {
if (_always_parse || (receives_input() && _trace_on)) {
MidiBuffer& mb (get_midi_buffer (nframes));
/* dump incoming MIDI to parser */
@ -116,6 +117,10 @@ MidiPort::get_midi_buffer (pframes_t nframes)
if (buf[0] == 0xfe) {
/* throw away active sensing */
continue;
} else if ((buf[0] & 0xF0) == 0x90 && buf[2] == 0) {
/* normalize note on with velocity 0 to proper note off */
buf[0] = 0x80 | (buf[0] & 0x0F); /* note off */
buf[2] = 0x40; /* default velocity */
}
/* check that the event is in the acceptable time range */
@ -203,10 +208,26 @@ MidiPort::flush_buffers (pframes_t nframes)
port_buffer = port_engine.get_buffer (_port_handle, nframes);
}
for (MidiBuffer::iterator i = _buffer->begin(); i != _buffer->end(); ++i) {
const Evoral::MIDIEvent<MidiBuffer::TimeType> ev (*i, false);
if (sends_output() && _trace_on) {
uint8_t const * const buf = ev.buffer();
const framepos_t now = AudioEngine::instance()->sample_time_at_cycle_start();
_self_parser.set_timestamp (now + ev.time());
uint32_t limit = ev.size();
for (size_t n = 0; n < limit; ++n) {
_self_parser.scanner (buf[n]);
}
}
// event times are in frames, relative to cycle start
#ifndef NDEBUG
@ -287,3 +308,9 @@ MidiPort::set_always_parse (bool yn)
{
_always_parse = yn;
}
void
MidiPort::set_trace_on (bool yn)
{
_trace_on = yn;
}

View file

@ -53,17 +53,14 @@ using namespace PBD;
namespace ARDOUR {
namespace Properties {
PBD::PropertyDescriptor<void*> midi_data;
PBD::PropertyDescriptor<Evoral::MusicalTime> start_beats;
PBD::PropertyDescriptor<Evoral::MusicalTime> length_beats;
PBD::PropertyDescriptor<Evoral::Beats> start_beats;
PBD::PropertyDescriptor<Evoral::Beats> length_beats;
}
}
void
MidiRegion::make_property_quarks ()
{
Properties::midi_data.property_id = g_quark_from_static_string (X_("midi-data"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for midi-data = %1\n", Properties::midi_data.property_id));
Properties::start_beats.property_id = g_quark_from_static_string (X_("start-beats"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for start-beats = %1\n", Properties::start_beats.property_id));
Properties::length_beats.property_id = g_quark_from_static_string (X_("length-beats"));
@ -80,7 +77,7 @@ MidiRegion::register_properties ()
/* Basic MidiRegion constructor (many channels) */
MidiRegion::MidiRegion (const SourceList& srcs)
: Region (srcs)
, _start_beats (Properties::start_beats, Evoral::MusicalTime())
, _start_beats (Properties::start_beats, Evoral::Beats())
, _length_beats (Properties::length_beats, midi_source(0)->length_beats())
{
register_properties ();
@ -94,7 +91,7 @@ MidiRegion::MidiRegion (const SourceList& srcs)
MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other)
: Region (other)
, _start_beats (Properties::start_beats, other->_start_beats)
, _length_beats (Properties::length_beats, Evoral::MusicalTime())
, _length_beats (Properties::length_beats, Evoral::Beats())
{
update_length_beats ();
register_properties ();
@ -107,11 +104,11 @@ MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other)
/** Create a new MidiRegion that is part of an existing one */
MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other, frameoffset_t offset)
: Region (other, offset)
, _start_beats (Properties::start_beats, Evoral::MusicalTime())
, _length_beats (Properties::length_beats, Evoral::MusicalTime())
, _start_beats (Properties::start_beats, Evoral::Beats())
, _length_beats (Properties::length_beats, Evoral::Beats())
{
BeatsFramesConverter bfc (_session.tempo_map(), _position);
Evoral::MusicalTime const offset_beats = bfc.from (offset);
Evoral::Beats const offset_beats = bfc.from (offset);
_start_beats = other->_start_beats.val() + offset_beats;
_length_beats = other->_length_beats.val() - offset_beats;
@ -147,8 +144,8 @@ boost::shared_ptr<MidiRegion>
MidiRegion::clone (boost::shared_ptr<MidiSource> newsrc) const
{
BeatsFramesConverter bfc (_session.tempo_map(), _position);
Evoral::MusicalTime const bbegin = bfc.from (_start);
Evoral::MusicalTime const bend = bfc.from (_start + _length);
Evoral::Beats const bbegin = bfc.from (_start);
Evoral::Beats const bend = bfc.from (_start + _length);
{
/* Lock our source since we'll be reading from it. write_to() will
@ -223,7 +220,7 @@ MidiRegion::set_position_internal (framepos_t pos, bool allow_bbt_recompute)
/* zero length regions don't exist - so if _length_beats is zero, this object
is under construction.
*/
if (_length_beats.val() == Evoral::MusicalTime()) {
if (_length_beats.val() == Evoral::Beats()) {
/* leave _length_beats alone, and change _length to reflect the state of things
at the new position (tempo map may dictate a different number of frames
*/
@ -233,9 +230,15 @@ MidiRegion::set_position_internal (framepos_t pos, bool allow_bbt_recompute)
}
framecnt_t
MidiRegion::read_at (Evoral::EventSink<framepos_t>& out, framepos_t position, framecnt_t dur, uint32_t chan_n, NoteMode mode, MidiStateTracker* tracker) const
MidiRegion::read_at (Evoral::EventSink<framepos_t>& out,
framepos_t position,
framecnt_t dur,
uint32_t chan_n,
NoteMode mode,
MidiStateTracker* tracker,
MidiChannelFilter* filter) const
{
return _read_at (_sources, out, position, dur, chan_n, mode, tracker);
return _read_at (_sources, out, position, dur, chan_n, mode, tracker, filter);
}
framecnt_t
@ -245,11 +248,17 @@ MidiRegion::master_read_at (MidiRingBuffer<framepos_t>& out, framepos_t position
}
framecnt_t
MidiRegion::_read_at (const SourceList& /*srcs*/, Evoral::EventSink<framepos_t>& dst, framepos_t position, framecnt_t dur, uint32_t chan_n,
NoteMode mode, MidiStateTracker* tracker) const
MidiRegion::_read_at (const SourceList& /*srcs*/,
Evoral::EventSink<framepos_t>& dst,
framepos_t position,
framecnt_t dur,
uint32_t chan_n,
NoteMode mode,
MidiStateTracker* tracker,
MidiChannelFilter* filter) const
{
frameoffset_t internal_offset = 0;
framecnt_t to_read = 0;
framecnt_t to_read = 0;
/* precondition: caller has verified that we cover the desired section */
@ -299,6 +308,7 @@ MidiRegion::_read_at (const SourceList& /*srcs*/, Evoral::EventSink<framepos_t>&
_start + internal_offset, // where to start reading in the source
to_read, // read duration in frames
tracker,
filter,
_filtered_parameters
) != to_read) {
return 0; /* "read nothing" */
@ -408,24 +418,6 @@ MidiRegion::model_changed ()
midi_source()->AutomationStateChanged.connect_same_thread (
_model_connection, boost::bind (&MidiRegion::model_automation_state_changed, this, _1)
);
model()->ContentsChanged.connect_same_thread (
_model_contents_connection, boost::bind (&MidiRegion::model_contents_changed, this));
}
void
MidiRegion::model_contents_changed ()
{
{
/* Invalidate source iterator to force reading new contents even if the
calls to read() progress linearly. Try-lock only to avoid deadlock
when called while writing with the source already locked. */
Glib::Threads::Mutex::Lock lm (midi_source(0)->mutex(), Glib::Threads::TRY_LOCK);
if (lm.locked()) {
midi_source(0)->invalidate (lm);
}
}
send_change (PropertyChange (Properties::midi_data));
}
void
@ -448,6 +440,7 @@ MidiRegion::model_automation_state_changed (Evoral::Parameter const & p)
*/
Glib::Threads::Mutex::Lock lm (midi_source(0)->mutex(), Glib::Threads::TRY_LOCK);
if (lm.locked()) {
/* TODO: This is too aggressive, we need more fine-grained invalidation. */
midi_source(0)->invalidate (lm);
}
}
@ -462,7 +455,7 @@ MidiRegion::fix_negative_start ()
model()->insert_silence_at_start (c.from (-_start));
_start = 0;
_start_beats = Evoral::MusicalTime();
_start_beats = Evoral::Beats();
}
/** Transpose the notes in this region by a given number of semitones */

View file

@ -60,6 +60,10 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame
ev_time = *(reinterpret_cast<T*>((uintptr_t)peekbuf));
ev_size = *(reinterpret_cast<uint32_t*>((uintptr_t)(peekbuf + sizeof(T) + sizeof (Evoral::EventType))));
if (this->read_space() < ev_size) {
break;;
}
if (ev_time >= end) {
DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 past end @ %2\n", ev_time, end));
break;
@ -124,6 +128,71 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame
return count;
}
template<typename T>
size_t
MidiRingBuffer<T>::skip_to(framepos_t start)
{
if (this->read_space() == 0) {
return 0;
}
T ev_time;
uint32_t ev_size;
size_t count = 0;
const size_t prefix_size = sizeof(T) + sizeof(Evoral::EventType) + sizeof(uint32_t);
while (this->read_space() >= prefix_size) {
uint8_t peekbuf[prefix_size];
this->peek (peekbuf, prefix_size);
ev_time = *(reinterpret_cast<T*>((uintptr_t)peekbuf));
ev_size = *(reinterpret_cast<uint32_t*>((uintptr_t)(peekbuf + sizeof(T) + sizeof (Evoral::EventType))));
if (ev_time >= start) {
return count;
}
if (this->read_space() < ev_size) {
continue;
}
this->increment_read_ptr (prefix_size);
uint8_t status;
bool r = this->peek (&status, sizeof(uint8_t));
assert (r); // If this failed, buffer is corrupt, all hope is lost
++count;
/* TODO investigate and think:
*
* Does it makes sense to keep track of notes
* that are skipped (because they're either too late
* (underrun) or never used (read-ahead, loop) ?
*
* skip_to() is called on the rinbuffer between
* disk and process. it seems wrong to track them
* (a potential synth never sees skipped notes, either)
* but there may be more to this.
*/
if (ev_size >= 8) {
this->increment_read_ptr (ev_size);
} else {
// we only track note on/off, 8 bytes are plenty.
uint8_t write_loc[8];
bool success = read_contents (ev_size, write_loc);
if (success) {
_tracker.track(write_loc);
}
}
}
return count;
}
template<typename T>
void
MidiRingBuffer<T>::flush (framepos_t /*start*/, framepos_t end)
@ -246,6 +315,13 @@ MidiRingBuffer<T>::resolve_tracker (MidiBuffer& dst, framepos_t t)
_tracker.resolve_notes (dst, t);
}
template<typename T>
void
MidiRingBuffer<T>::resolve_tracker (Evoral::EventSink<framepos_t>& dst, framepos_t t)
{
_tracker.resolve_notes(dst, t);
}
template class MidiRingBuffer<framepos_t>;
} // namespace ARDOUR

View file

@ -38,10 +38,11 @@
#include "evoral/EventSink.hpp"
#include "ardour/debug.h"
#include "ardour/midi_model.h"
#include "ardour/midi_state_tracker.h"
#include "ardour/midi_source.h"
#include "ardour/file_source.h"
#include "ardour/midi_channel_filter.h"
#include "ardour/midi_model.h"
#include "ardour/midi_source.h"
#include "ardour/midi_state_tracker.h"
#include "ardour/session.h"
#include "ardour/session_directory.h"
#include "ardour/source_factory.h"
@ -177,10 +178,10 @@ MidiSource::update_length (framecnt_t)
}
void
MidiSource::invalidate (const Lock& lock)
MidiSource::invalidate (const Lock& lock, std::set<Evoral::Sequence<Evoral::Beats>::WeakNotePtr>* notes)
{
_model_iter_valid = false;
_model_iter.invalidate();
_model_iter.invalidate(notes);
}
framecnt_t
@ -190,6 +191,7 @@ MidiSource::midi_read (const Lock& lm,
framepos_t start,
framecnt_t cnt,
MidiStateTracker* tracker,
MidiChannelFilter* filter,
const std::set<Evoral::Parameter>& filtered) const
{
BeatsFramesConverter converter(_session.tempo_map(), source_start);
@ -200,11 +202,16 @@ MidiSource::midi_read (const Lock& lm,
if (_model) {
// Find appropriate model iterator
Evoral::Sequence<Evoral::MusicalTime>::const_iterator& i = _model_iter;
if (_last_read_end == 0 || start != _last_read_end || !_model_iter_valid) {
Evoral::Sequence<Evoral::Beats>::const_iterator& i = _model_iter;
const bool linear_read = _last_read_end != 0 && start == _last_read_end;
if (!linear_read || !_model_iter_valid) {
// Cached iterator is invalid, search for the first event past start
i = _model->begin(converter.from(start), false, filtered);
i = _model->begin(converter.from(start), false, filtered,
linear_read ? &_model->active_notes() : NULL);
_model_iter_valid = true;
if (!linear_read) {
_model->active_notes().clear();
}
}
_last_read_end = start + cnt;
@ -213,6 +220,13 @@ MidiSource::midi_read (const Lock& lm,
for (; i != _model->end(); ++i) {
const framecnt_t time_frames = converter.to(i->time());
if (time_frames < start + cnt) {
if (filter && filter->filter(i->buffer(), i->size())) {
DEBUG_TRACE (DEBUG::MidiSourceIO,
string_compose ("%1: filter event @ %2 type %3 size %4\n",
_name, time_frames + source_start, i->event_type(), i->size()));
continue;
}
// Offset by source start to convert event time to session time
dst.write (time_frames + source_start, i->event_type(), i->size(), i->buffer());
@ -232,7 +246,7 @@ MidiSource::midi_read (const Lock& lm,
}
return cnt;
} else {
return read_unlocked (lm, dst, source_start, start, cnt, tracker);
return read_unlocked (lm, dst, source_start, start, cnt, tracker, filter);
}
}
@ -297,9 +311,9 @@ MidiSource::mark_streaming_write_started (const Lock& lock)
}
void
MidiSource::mark_midi_streaming_write_completed (const Lock& lock,
Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption option,
Evoral::MusicalTime end)
MidiSource::mark_midi_streaming_write_completed (const Lock& lock,
Evoral::Sequence<Evoral::Beats>::StuckNoteOption option,
Evoral::Beats end)
{
if (_model) {
_model->end_write (option, end);
@ -320,11 +334,11 @@ MidiSource::mark_midi_streaming_write_completed (const Lock&
void
MidiSource::mark_streaming_write_completed (const Lock& lock)
{
mark_midi_streaming_write_completed (lock, Evoral::Sequence<Evoral::MusicalTime>::DeleteStuckNotes);
mark_midi_streaming_write_completed (lock, Evoral::Sequence<Evoral::Beats>::DeleteStuckNotes);
}
int
MidiSource::write_to (const Lock& lock, boost::shared_ptr<MidiSource> newsrc, Evoral::MusicalTime begin, Evoral::MusicalTime end)
MidiSource::write_to (const Lock& lock, boost::shared_ptr<MidiSource> newsrc, Evoral::Beats begin, Evoral::Beats end)
{
Lock newsrc_lock (newsrc->mutex ());
@ -333,7 +347,7 @@ MidiSource::write_to (const Lock& lock, boost::shared_ptr<MidiSource> newsrc, Ev
newsrc->copy_automation_state_from (this);
if (_model) {
if (begin == Evoral::MinMusicalTime && end == Evoral::MaxMusicalTime) {
if (begin == Evoral::MinBeats && end == Evoral::MaxBeats) {
_model->write_to (newsrc, newsrc_lock);
} else {
_model->write_section_to (newsrc, newsrc_lock, begin, end);
@ -347,7 +361,7 @@ MidiSource::write_to (const Lock& lock, boost::shared_ptr<MidiSource> newsrc, Ev
/* force a reload of the model if the range is partial */
if (begin != Evoral::MinMusicalTime || end != Evoral::MaxMusicalTime) {
if (begin != Evoral::MinBeats || end != Evoral::MaxBeats) {
newsrc->load_model (newsrc_lock, true);
} else {
newsrc->set_model (newsrc_lock, _model);

View file

@ -168,7 +168,7 @@ MidiStateTracker::resolve_notes (Evoral::EventSink<framepos_t> &dst, framepos_t
}
void
MidiStateTracker::resolve_notes (MidiSource& src, const MidiSource::Lock& lock, Evoral::MusicalTime time)
MidiStateTracker::resolve_notes (MidiSource& src, const MidiSource::Lock& lock, Evoral::Beats time)
{
DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1 MS-resolve notes @ %2 on = %3\n", this, time, _on));
@ -181,7 +181,7 @@ MidiStateTracker::resolve_notes (MidiSource& src, const MidiSource::Lock& lock,
for (int channel = 0; channel < 16; ++channel) {
for (int note = 0; note < 128; ++note) {
while (_active_notes[note + 128 * channel]) {
Evoral::MIDIEvent<Evoral::MusicalTime> ev ((MIDI_CMD_NOTE_OFF|channel), time, 3, 0, true);
Evoral::MIDIEvent<Evoral::Beats> ev ((MIDI_CMD_NOTE_OFF|channel), time, 3, 0, true);
ev.set_type (MIDI_CMD_NOTE_OFF);
ev.set_channel (channel);
ev.set_note (note);
@ -191,7 +191,7 @@ MidiStateTracker::resolve_notes (MidiSource& src, const MidiSource::Lock& lock,
this, (int) note, (int) channel, time));
_active_notes[note + 128 * channel]--;
/* don't stack events up at the same time */
time += Evoral::MusicalTime::tick();
time += Evoral::Beats::tick();
}
}
}

View file

@ -108,7 +108,7 @@ MidiStretch::run (boost::shared_ptr<Region> r, Progress*)
new_model->append(ev, Evoral::next_event_id());
}
new_model->end_write (Evoral::Sequence<Evoral::MusicalTime>::DeleteStuckNotes);
new_model->end_write (Evoral::Sequence<Evoral::Beats>::DeleteStuckNotes);
new_model->set_edited (true);
new_src->copy_interpolation_from (src);

View file

@ -29,11 +29,11 @@
#define isnan_local std::isnan
#endif
#include "pbd/ffs.h"
#include "pbd/enumwriter.h"
#include "pbd/convert.h"
#include "evoral/midi_util.h"
#include "ardour/beats_frames_converter.h"
#include "ardour/buffer_set.h"
#include "ardour/debug.h"
#include "ardour/delivery.h"
@ -42,6 +42,7 @@
#include "ardour/midi_diskstream.h"
#include "ardour/midi_playlist.h"
#include "ardour/midi_port.h"
#include "ardour/midi_region.h"
#include "ardour/midi_track.h"
#include "ardour/parameter_types.h"
#include "ardour/port.h"
@ -70,8 +71,6 @@ MidiTrack::MidiTrack (Session& sess, string name, Route::Flag flag, TrackMode mo
, _note_mode(Sustained)
, _step_editing (false)
, _input_active (true)
, _playback_channel_mask(0x0000ffff)
, _capture_channel_mask(0x0000ffff)
{
}
@ -258,7 +257,7 @@ MidiTrack::set_state_part_two ()
{
XMLNode* fnode;
XMLProperty* prop;
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
/* This is called after all session state has been restored but before
have been made ports and connections are established.
@ -318,6 +317,20 @@ MidiTrack::set_state_part_two ()
return;
}
void
MidiTrack::update_controls(const BufferSet& bufs)
{
const MidiBuffer& buf = bufs.get_midi(0);
for (MidiBuffer::const_iterator e = buf.begin(); e != buf.end(); ++e) {
const Evoral::MIDIEvent<framepos_t>& ev = *e;
const Evoral::Parameter param = midi_parameter(ev.buffer(), ev.size());
const boost::shared_ptr<Evoral::Control> control = this->control(param);
if (control) {
control->set_double(ev.value(), _session.transport_frame(), false);
}
}
}
/** @param need_butler to be set to true if this track now needs the butler, otherwise it can be left alone
* or set to false.
*/
@ -370,13 +383,13 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
fill_buffers_with_input (bufs, _input, nframes);
/* filter captured data before meter sees it */
_capture_filter.filter (bufs);
if (_meter_point == MeterInput && (_monitoring & MonitorInput || _diskstream->record_enabled())) {
_meter->run (bufs, start_frame, end_frame, nframes, true);
}
/* filter captured data before the diskstream sees it */
filter_channels (bufs, get_capture_channel_mode(), get_capture_channel_mask());
_silent = false;
@ -386,9 +399,7 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
return dret;
}
/* filter playback data before we do anything else */
filter_channels (bufs, get_playback_channel_mode(), get_playback_channel_mask ());
/* note diskstream uses our filter to filter/map playback channels appropriately. */
if (monitoring_state() == MonitoringInput) {
@ -470,6 +481,42 @@ MidiTrack::realtime_handle_transport_stopped ()
}
}
void
MidiTrack::non_realtime_locate (framepos_t pos)
{
Track::non_realtime_locate(pos);
boost::shared_ptr<MidiPlaylist> playlist = midi_diskstream()->midi_playlist();
if (!playlist) {
return;
}
/* Get the top unmuted region at this position. */
boost::shared_ptr<MidiRegion> region = boost::dynamic_pointer_cast<MidiRegion>(
playlist->top_unmuted_region_at(pos));
if (!region) {
return;
}
Glib::Threads::Mutex::Lock lm (_control_lock, Glib::Threads::TRY_LOCK);
if (!lm.locked()) {
return;
}
/* Update track controllers based on its "automation". */
const framepos_t origin = region->position() - region->start();
BeatsFramesConverter bfc(_session.tempo_map(), origin);
for (Controls::const_iterator c = _controls.begin(); c != _controls.end(); ++c) {
boost::shared_ptr<MidiTrack::MidiControl> tcontrol;
boost::shared_ptr<Evoral::Control> rcontrol;
if ((tcontrol = boost::dynamic_pointer_cast<MidiTrack::MidiControl>(c->second)) &&
(rcontrol = region->control(tcontrol->parameter()))) {
const Evoral::Beats pos_beats = bfc.from(pos - origin);
tcontrol->set_value(rcontrol->list()->eval(pos_beats.to_double()));
}
}
}
void
MidiTrack::push_midi_input_to_step_edit_ringbuffer (framecnt_t nframes)
{
@ -497,48 +544,13 @@ MidiTrack::push_midi_input_to_step_edit_ringbuffer (framecnt_t nframes)
}
}
void
MidiTrack::filter_channels (BufferSet& bufs, ChannelMode mode, uint32_t mask)
{
if (mode == AllChannels) {
return;
}
MidiBuffer& buf (bufs.get_midi (0));
for (MidiBuffer::iterator e = buf.begin(); e != buf.end(); ) {
Evoral::MIDIEvent<framepos_t> ev(*e, false);
if (ev.is_channel_event()) {
switch (mode) {
case FilterChannels:
if (0 == ((1<<ev.channel()) & mask)) {
e = buf.erase (e);
} else {
++e;
}
break;
case ForceChannel:
ev.set_channel (PBD::ffs (mask) - 1);
++e;
break;
case AllChannels:
/* handled by the opening if() */
++e;
break;
}
} else {
++e;
}
}
}
void
MidiTrack::write_out_of_band_data (BufferSet& bufs, framepos_t /*start*/, framepos_t /*end*/, framecnt_t nframes)
{
MidiBuffer& buf (bufs.get_midi (0));
update_controls (bufs);
// Append immediate events
if (_immediate_events.read_space()) {
@ -761,52 +773,34 @@ MidiTrack::write_source (uint32_t)
}
void
MidiTrack::set_playback_channel_mode(ChannelMode mode, uint16_t mask)
MidiTrack::set_playback_channel_mode(ChannelMode mode, uint16_t mask)
{
ChannelMode old = get_playback_channel_mode ();
uint16_t old_mask = get_playback_channel_mask ();
if (old != mode || mask != old_mask) {
_set_playback_channel_mode (mode, mask);
PlaybackChannelModeChanged ();
_session.set_dirty ();
if (_playback_filter.set_channel_mode(mode, mask)) {
_session.set_dirty();
}
}
void
MidiTrack::set_capture_channel_mode(ChannelMode mode, uint16_t mask)
MidiTrack::set_capture_channel_mode(ChannelMode mode, uint16_t mask)
{
ChannelMode old = get_capture_channel_mode ();
uint16_t old_mask = get_capture_channel_mask ();
if (old != mode || mask != old_mask) {
_set_capture_channel_mode (mode, mask);
CaptureChannelModeChanged ();
_session.set_dirty ();
if (_capture_filter.set_channel_mode(mode, mask)) {
_session.set_dirty();
}
}
void
MidiTrack::set_playback_channel_mask (uint16_t mask)
{
uint16_t old = get_playback_channel_mask();
if (old != mask) {
_set_playback_channel_mask (mask);
PlaybackChannelMaskChanged ();
_session.set_dirty ();
if (_playback_filter.set_channel_mask(mask)) {
_session.set_dirty();
}
}
void
MidiTrack::set_capture_channel_mask (uint16_t mask)
{
uint16_t old = get_capture_channel_mask();
if (old != mask) {
_set_capture_channel_mask (mask);
CaptureChannelMaskChanged ();
_session.set_dirty ();
if (_capture_filter.set_channel_mask(mask)) {
_session.set_dirty();
}
}
@ -892,10 +886,10 @@ MidiTrack::act_on_mute ()
return;
}
if (muted()) {
if (muted() || _mute_master->muted_by_others_at(MuteMaster::AllPoints)) {
/* only send messages for channels we are using */
uint16_t mask = get_playback_channel_mask();
uint16_t mask = _playback_filter.get_channel_mask();
for (uint8_t channel = 0; channel <= 0xF; channel++) {
@ -904,10 +898,14 @@ MidiTrack::act_on_mute ()
DEBUG_TRACE (DEBUG::MidiIO, string_compose ("%1 delivers mute message to channel %2\n", name(), channel+1));
uint8_t ev[3] = { ((uint8_t) (MIDI_CMD_CONTROL | channel)), MIDI_CTL_SUSTAIN, 0 };
write_immediate_event (3, ev);
ev[1] = MIDI_CTL_ALL_NOTES_OFF;
write_immediate_event (3, ev);
/* Note we do not send MIDI_CTL_ALL_NOTES_OFF here, since this may
silence notes that came from another non-muted track. */
}
}
/* Resolve active notes. */
midi_diskstream()->resolve_tracker(_immediate_events, 0);
}
}

View file

@ -224,7 +224,7 @@ MonitorProcessor::set_state (const XMLNode& node, int version)
XMLNode&
MonitorProcessor::state (bool full)
{
LocaleGuard lg (X_("POSIX"));
LocaleGuard lg (X_("C"));
XMLNode& node (Processor::state (full));
char buf[64];
@ -301,8 +301,7 @@ MonitorProcessor::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /
if (target_gain != _channels[chn]->current_gain || target_gain != 1.0f) {
Amp::apply_gain (*b, nframes, _channels[chn]->current_gain, target_gain);
_channels[chn]->current_gain = target_gain;
_channels[chn]->current_gain = Amp::apply_gain (*b, _session.nominal_frame_rate(), nframes, _channels[chn]->current_gain, target_gain);
}
++chn;

Some files were not shown because too many files have changed in this diff Show more