mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-06 13:45:43 +01:00
Merge branch 'master' into saveas
Conflicts: gtk2_ardour/ardour.menus.in libs/ardour/session_state.cc
This commit is contained in:
commit
ced4378d09
602 changed files with 94298 additions and 65112 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
AdditionalOptions="/FI$(TargetSxsFolder)\targetsxs.h"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..;..\..\ardour;..\..\pbd;..\..\fst;"$(GenericIncludeFolder)\ardourext";..\..\surfaces\control_protocol;..\..\evoral;..\..\libltc;..\..\timecode;"..\..\midi++2";..\..\audiographer;"$(GenericIncludeFolder)\taglib";"$(GenericIncludeFolder)\taglib\toolkit";"$(GenericLibraryFolder)\glib-2.0\include";"$(GenericIncludeFolder)\glibmm";"$(GenericIncludeFolder)\libsndfile";"$(GenericIncludeFolder)\gtk-2.0";"$(GenericIncludeFolder)\cairo";"$(GenericIncludeFolder)\pango-1.0";"$(GenericIncludeFolder)\gtk-2.0\gdk";"$(GenericIncludeFolder)\atk-2.0";"$(GenericIncludeFolder)\lrdf";"$(GenericIncludeFolder)\raptor";"$(GenericIncludeFolder)\lilv-0";"$(GenericIncludeFolder)\suil-0";"$(GenericIncludeFolder)\serd-0";"$(GenericIncludeFolder)\sord-0";"$(GenericIncludeFolder)\lv2";"$(GenericIncludeFolder)\sratom-0""
|
||||
PreprocessorDefinitions="PLATFORM_WINDOWS;COMPILER_MSVC;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="Debug";ARCH_X86;USE_XMMINTRIN;ENABLE_NLS;PACKAGE="\"ardour3\"";PROGRAM_NAME="\"Mixbus3\"";PROGRAM_VERSION="\"\"";_REENTRANT;_USE_MATH_DEFINES;_LARGEFILE_SOURCE;_LARGEFILE64_SOURCE;LIBC_DISABLE_DEPRECATED;BOOST_SYSTEM_NO_DEPRECATED;__STDC_LIMIT_MACROS;__STDC_FORMAT_MACROS;INTERNAL_SHARED_LIBS=1;JACK_SESSION=1;HAVE_GLIB=1;HAVE_GTHREAD=1;HAVE_SNDFILE=1;HAVE_GIOMM=1;HAVE_CURL=1;HAVE_LO=1;HAVE_MODE_T=1;PHONE_HOME=1;FREESOUND=1;WINDOWS_KEY=\"Mod4><Super\";IS_OSX=0;HAVE_XML=1;HAVE_UUID=1;HAVE_LIBS_PBD=1;HAVE_JACK=1;HAVE_LIBS_MIDIPP2=1;HAVE_LIBS_EVORAL=1;HAVE_FFTW3=1;HAVE_FFTW3F=1;HAVE_AUBIO=1;HAVE_LIBS_VAMP_SDK=1;HAVE_LIBS_VAMP_PLUGINS=1;HAVE_LIBS_TAGLIB=1;HAVE_LIBS_LIBLTC=1;HAVE_LIBS_RUBBERBAND=1;HAVE_CONTROL_PROTOCOL=1;HAVE_FRONTIER=1;HAVE_GENERIC_MIDI=1;HAVE_MACKIE=1;HAVE_OSC=1;HAVE_TRANZPORT=1;HAVE_WIIMOTE=1;HAVE_LIBS_SURFACES=1;HAVE_2IN2OUT=1;HAVE_1IN2OUT=1;HAVE_VBAP=1;HAVE_LIBS_PANNERS=1;HAVE_LIBS_TIMECODE=1;HAVE_LRDF=1;HAVE_SAMPLERATE=1;HAVE_SERD=1;HAVE_SORD=1;HAVE_SRATOM=1;HAVE_LILV=1;HAVE_LILV_0_16_0=1;HAVE_OGG=1;HAVE_FLAC=1;HAVE_RUBBERBAND=1;USE_RUBBERBAND=1;HAVE_JACK_SESSION=1;HAVE_UNISTD=1;HAVE_JACK_ON_INFO_SHUTDOWN=1;HAVE_JACK_VIDEO_SUPPORT=1;HAVE_BOOST_SCOPED_PTR_HPP=1;HAVE_BOOST_PTR_CONTAINER_PTR_LIST_HPP=1;HAVE_LIBS_ARDOUR=1;HAVE_GTKMM=1;HAVE_GTK=1;HAVE_LIBS_GTKMM2EXT=1;HAVE_LIBS_CLEARLOOKS_NEWER=1;HAVE_BOOST_FORMAT_HPP=1;HAVE_LIBS_AUDIOGRAPHER=1;HAVE_GNOMECANVAS=0;HAVE_GNOMECANVASMM=0;HAVE_X11=0;HAVE_FONTCONFIG=1;HAVE_BOOST_SHARED_PTR_HPP=1;HAVE_BOOST_WEAK_PTR_HPP=1;HAVE_GTK2_ARDOUR=1;HAVE_EXPORT=1;HAVE_MIDI_MAPS=1;HAVE_MCP=1;HAVE_PATCHFILES=1;HAVE_TOOLS_SANITY_CHECK=1;SMF_VERSION=\"1.2\";CURRENT_SESSION_FILE_VERSION=3001"
|
||||
PreprocessorDefinitions="PLATFORM_WINDOWS;COMPILER_MSVC;DEBUGGABLE_BACKENDS;DEBUGGABLE_SCANNER_APP;BUILDING_LIBARDOUR;LIBARDOUR_DLL_EXPORTS;LIBARDOUR=\"mixbus3\";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="Debug";ARCH_X86;USE_XMMINTRIN;ENABLE_NLS;PACKAGE="\"ardour3\"";PROGRAM_NAME="\"Mixbus\"";PROGRAM_VERSION="\"3\"";_REENTRANT;_USE_MATH_DEFINES;_LARGEFILE_SOURCE;_LARGEFILE64_SOURCE;LIBC_DISABLE_DEPRECATED;BOOST_SYSTEM_NO_DEPRECATED;__STDC_LIMIT_MACROS;__STDC_FORMAT_MACROS;INTERNAL_SHARED_LIBS=1;JACK_SESSION=1;HAVE_GLIB=1;HAVE_GTHREAD=1;HAVE_SNDFILE=1;HAVE_GIOMM=1;HAVE_CURL=1;HAVE_LO=1;HAVE_MODE_T=1;PHONE_HOME=1;FREESOUND=1;WINDOWS_KEY=\"Mod4><Super\";IS_OSX=0;HAVE_XML=1;HAVE_UUID=1;HAVE_LIBS_PBD=1;HAVE_JACK=1;HAVE_LIBS_MIDIPP2=1;HAVE_LIBS_EVORAL=1;HAVE_FFTW3=1;HAVE_FFTW3F=1;HAVE_AUBIO=1;HAVE_LIBS_VAMP_SDK=1;HAVE_LIBS_VAMP_PLUGINS=1;HAVE_LIBS_TAGLIB=1;HAVE_LIBS_LIBLTC=1;HAVE_LIBS_RUBBERBAND=1;HAVE_CONTROL_PROTOCOL=1;HAVE_FRONTIER=1;HAVE_GENERIC_MIDI=1;HAVE_MACKIE=1;HAVE_OSC=1;HAVE_TRANZPORT=1;HAVE_WIIMOTE=1;HAVE_LIBS_SURFACES=1;HAVE_2IN2OUT=1;HAVE_1IN2OUT=1;HAVE_VBAP=1;HAVE_LIBS_PANNERS=1;HAVE_LIBS_TIMECODE=1;HAVE_LRDF=1;HAVE_SAMPLERATE=1;HAVE_SERD=1;HAVE_SORD=1;HAVE_SRATOM=1;HAVE_LILV=1;HAVE_LILV_0_16_0=1;HAVE_OGG=1;HAVE_FLAC=1;HAVE_RUBBERBAND=1;USE_RUBBERBAND=1;HAVE_JACK_SESSION=1;HAVE_UNISTD=1;HAVE_JACK_ON_INFO_SHUTDOWN=1;HAVE_JACK_VIDEO_SUPPORT=1;HAVE_BOOST_SCOPED_PTR_HPP=1;HAVE_BOOST_PTR_CONTAINER_PTR_LIST_HPP=1;HAVE_LIBS_ARDOUR=1;HAVE_GTKMM=1;HAVE_GTK=1;HAVE_LIBS_GTKMM2EXT=1;HAVE_LIBS_CLEARLOOKS_NEWER=1;HAVE_BOOST_FORMAT_HPP=1;HAVE_LIBS_AUDIOGRAPHER=1;HAVE_GNOMECANVAS=0;HAVE_GNOMECANVASMM=0;HAVE_X11=0;HAVE_FONTCONFIG=1;HAVE_BOOST_SHARED_PTR_HPP=1;HAVE_BOOST_WEAK_PTR_HPP=1;HAVE_GTK2_ARDOUR=1;HAVE_EXPORT=1;HAVE_MIDI_MAPS=1;HAVE_MCP=1;HAVE_PATCHFILES=1;HAVE_TOOLS_SANITY_CHECK=1;SMF_VERSION=\"1.2\";CURRENT_SESSION_FILE_VERSION=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;"$(GenericIncludeFolder)\ardourext";..\..\surfaces\control_protocol;..\..\evoral;..\..\libltc;..\..\timecode;"..\..\midi++2";..\..\audiographer;"$(GenericIncludeFolder)\taglib";"$(GenericIncludeFolder)\taglib\toolkit";"$(GenericLibraryFolder)\glib-2.0\include";"$(GenericIncludeFolder)\glibmm";"$(GenericIncludeFolder)\libsndfile";"$(GenericIncludeFolder)\gtk-2.0";"$(GenericIncludeFolder)\cairo";"$(GenericIncludeFolder)\pango-1.0";"$(GenericIncludeFolder)\gtk-2.0\gdk";"$(GenericIncludeFolder)\atk-2.0";"$(GenericIncludeFolder)\lrdf";"$(GenericIncludeFolder)\raptor";"$(GenericIncludeFolder)\lilv-0";"$(GenericIncludeFolder)\suil-0";"$(GenericIncludeFolder)\serd-0";"$(GenericIncludeFolder)\sord-0";"$(GenericIncludeFolder)\lv2";"$(GenericIncludeFolder)\sratom-0""
|
||||
PreprocessorDefinitions="PLATFORM_WINDOWS;COMPILER_MSVC;_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="\"ardour3\"";PROGRAM_NAME="\"Mixbus3\"";PROGRAM_VERSION="\"\"";_REENTRANT;_USE_MATH_DEFINES;_LARGEFILE_SOURCE;_LARGEFILE64_SOURCE;LIBC_DISABLE_DEPRECATED;BOOST_SYSTEM_NO_DEPRECATED;__STDC_LIMIT_MACROS;__STDC_FORMAT_MACROS;INTERNAL_SHARED_LIBS=1;JACK_SESSION=1;HAVE_GLIB=1;HAVE_GTHREAD=1;HAVE_SNDFILE=1;HAVE_GIOMM=1;HAVE_CURL=1;HAVE_LO=1;HAVE_MODE_T=1;PHONE_HOME=1;FREESOUND=1;WINDOWS_KEY=\"Mod4><Super\";IS_OSX=0;HAVE_XML=1;HAVE_UUID=1;HAVE_LIBS_PBD=1;HAVE_JACK=1;HAVE_LIBS_MIDIPP2=1;HAVE_LIBS_EVORAL=1;HAVE_FFTW3=1;HAVE_FFTW3F=1;HAVE_AUBIO=1;HAVE_LIBS_VAMP_SDK=1;HAVE_LIBS_VAMP_PLUGINS=1;HAVE_LIBS_TAGLIB=1;HAVE_LIBS_LIBLTC=1;HAVE_LIBS_RUBBERBAND=1;HAVE_CONTROL_PROTOCOL=1;HAVE_FRONTIER=1;HAVE_GENERIC_MIDI=1;HAVE_MACKIE=1;HAVE_OSC=1;HAVE_TRANZPORT=1;HAVE_WIIMOTE=1;HAVE_LIBS_SURFACES=1;HAVE_2IN2OUT=1;HAVE_1IN2OUT=1;HAVE_VBAP=1;HAVE_LIBS_PANNERS=1;HAVE_LIBS_TIMECODE=1;HAVE_LRDF=1;HAVE_SAMPLERATE=1;HAVE_SERD=1;HAVE_SORD=1;HAVE_SRATOM=1;HAVE_LILV=1;HAVE_LILV_0_16_0=1;HAVE_OGG=1;HAVE_FLAC=1;HAVE_RUBBERBAND=1;USE_RUBBERBAND=1;HAVE_JACK_SESSION=1;HAVE_UNISTD=1;HAVE_JACK_ON_INFO_SHUTDOWN=1;HAVE_JACK_VIDEO_SUPPORT=1;HAVE_BOOST_SCOPED_PTR_HPP=1;HAVE_BOOST_PTR_CONTAINER_PTR_LIST_HPP=1;HAVE_LIBS_ARDOUR=1;HAVE_GTKMM=1;HAVE_GTK=1;HAVE_LIBS_GTKMM2EXT=1;HAVE_LIBS_CLEARLOOKS_NEWER=1;HAVE_BOOST_FORMAT_HPP=1;HAVE_LIBS_AUDIOGRAPHER=1;HAVE_GNOMECANVAS=0;HAVE_GNOMECANVASMM=0;HAVE_X11=0;HAVE_FONTCONFIG=1;HAVE_BOOST_SHARED_PTR_HPP=1;HAVE_BOOST_WEAK_PTR_HPP=1;HAVE_GTK2_ARDOUR=1;HAVE_EXPORT=1;HAVE_MIDI_MAPS=1;HAVE_MCP=1;HAVE_PATCHFILES=1;HAVE_TOOLS_SANITY_CHECK=1;SMF_VERSION=\"1.2\";CURRENT_SESSION_FILE_VERSION=3001"
|
||||
PreprocessorDefinitions="PLATFORM_WINDOWS;COMPILER_MSVC;_SECURE_SCL=0;BUILDING_LIBARDOUR;LIBARDOUR_DLL_EXPORTS;LIBARDOUR=\"mixbus3\";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="\"ardour3\"";PROGRAM_NAME="\"Mixbus\"";PROGRAM_VERSION="\"3\"";_REENTRANT;_USE_MATH_DEFINES;_LARGEFILE_SOURCE;_LARGEFILE64_SOURCE;LIBC_DISABLE_DEPRECATED;BOOST_SYSTEM_NO_DEPRECATED;__STDC_LIMIT_MACROS;__STDC_FORMAT_MACROS;INTERNAL_SHARED_LIBS=1;JACK_SESSION=1;HAVE_GLIB=1;HAVE_GTHREAD=1;HAVE_SNDFILE=1;HAVE_GIOMM=1;HAVE_CURL=1;HAVE_LO=1;HAVE_MODE_T=1;PHONE_HOME=1;FREESOUND=1;WINDOWS_KEY=\"Mod4><Super\";IS_OSX=0;HAVE_XML=1;HAVE_UUID=1;HAVE_LIBS_PBD=1;HAVE_JACK=1;HAVE_LIBS_MIDIPP2=1;HAVE_LIBS_EVORAL=1;HAVE_FFTW3=1;HAVE_FFTW3F=1;HAVE_AUBIO=1;HAVE_LIBS_VAMP_SDK=1;HAVE_LIBS_VAMP_PLUGINS=1;HAVE_LIBS_TAGLIB=1;HAVE_LIBS_LIBLTC=1;HAVE_LIBS_RUBBERBAND=1;HAVE_CONTROL_PROTOCOL=1;HAVE_FRONTIER=1;HAVE_GENERIC_MIDI=1;HAVE_MACKIE=1;HAVE_OSC=1;HAVE_TRANZPORT=1;HAVE_WIIMOTE=1;HAVE_LIBS_SURFACES=1;HAVE_2IN2OUT=1;HAVE_1IN2OUT=1;HAVE_VBAP=1;HAVE_LIBS_PANNERS=1;HAVE_LIBS_TIMECODE=1;HAVE_LRDF=1;HAVE_SAMPLERATE=1;HAVE_SERD=1;HAVE_SORD=1;HAVE_SRATOM=1;HAVE_LILV=1;HAVE_LILV_0_16_0=1;HAVE_OGG=1;HAVE_FLAC=1;HAVE_RUBBERBAND=1;USE_RUBBERBAND=1;HAVE_JACK_SESSION=1;HAVE_UNISTD=1;HAVE_JACK_ON_INFO_SHUTDOWN=1;HAVE_JACK_VIDEO_SUPPORT=1;HAVE_BOOST_SCOPED_PTR_HPP=1;HAVE_BOOST_PTR_CONTAINER_PTR_LIST_HPP=1;HAVE_LIBS_ARDOUR=1;HAVE_GTKMM=1;HAVE_GTK=1;HAVE_LIBS_GTKMM2EXT=1;HAVE_LIBS_CLEARLOOKS_NEWER=1;HAVE_BOOST_FORMAT_HPP=1;HAVE_LIBS_AUDIOGRAPHER=1;HAVE_GNOMECANVAS=0;HAVE_GNOMECANVASMM=0;HAVE_X11=0;HAVE_FONTCONFIG=1;HAVE_BOOST_SHARED_PTR_HPP=1;HAVE_BOOST_WEAK_PTR_HPP=1;HAVE_GTK2_ARDOUR=1;HAVE_EXPORT=1;HAVE_MIDI_MAPS=1;HAVE_MCP=1;HAVE_PATCHFILES=1;HAVE_TOOLS_SANITY_CHECK=1;SMF_VERSION=\"1.2\";CURRENT_SESSION_FILE_VERSION=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;"$(GenericIncludeFolder)\ardourext";..\..\surfaces\control_protocol;..\..\evoral;..\..\libltc;..\..\timecode;"..\..\midi++2";..\..\audiographer;"$(GenericIncludeFolder)\taglib";"$(GenericIncludeFolder)\taglib\toolkit";"$(GenericLibraryFolder)\glib-2.0\include";"$(GenericIncludeFolder)\glibmm";"$(GenericIncludeFolder)\libsndfile";"$(GenericIncludeFolder)\gtk-2.0";"$(GenericIncludeFolder)\cairo";"$(GenericIncludeFolder)\pango-1.0";"$(GenericIncludeFolder)\gtk-2.0\gdk";"$(GenericIncludeFolder)\atk-2.0";"$(GenericIncludeFolder)\lrdf";"$(GenericIncludeFolder)\raptor";"$(GenericIncludeFolder)\lilv-0";"$(GenericIncludeFolder)\suil-0";"$(GenericIncludeFolder)\serd-0";"$(GenericIncludeFolder)\sord-0";"$(GenericIncludeFolder)\lv2";"$(GenericIncludeFolder)\sratom-0""
|
||||
PreprocessorDefinitions="PLATFORM_WINDOWS;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="\"ardour3\"";PROGRAM_NAME="\"Mixbus3\"";PROGRAM_VERSION="\"\"";_REENTRANT;_USE_MATH_DEFINES;_LARGEFILE_SOURCE;_LARGEFILE64_SOURCE;LIBC_DISABLE_DEPRECATED;BOOST_SYSTEM_NO_DEPRECATED;__STDC_LIMIT_MACROS;__STDC_FORMAT_MACROS;INTERNAL_SHARED_LIBS=1;JACK_SESSION=1;HAVE_GLIB=1;HAVE_GTHREAD=1;HAVE_SNDFILE=1;HAVE_GIOMM=1;HAVE_CURL=1;HAVE_LO=1;HAVE_MODE_T=1;PHONE_HOME=1;FREESOUND=1;WINDOWS_KEY=\"Mod4><Super\";IS_OSX=0;HAVE_XML=1;HAVE_UUID=1;HAVE_LIBS_PBD=1;HAVE_JACK=1;HAVE_LIBS_MIDIPP2=1;HAVE_LIBS_EVORAL=1;HAVE_FFTW3=1;HAVE_FFTW3F=1;HAVE_AUBIO=1;HAVE_LIBS_VAMP_SDK=1;HAVE_LIBS_VAMP_PLUGINS=1;HAVE_LIBS_TAGLIB=1;HAVE_LIBS_LIBLTC=1;HAVE_LIBS_RUBBERBAND=1;HAVE_CONTROL_PROTOCOL=1;HAVE_FRONTIER=1;HAVE_GENERIC_MIDI=1;HAVE_MACKIE=1;HAVE_OSC=1;HAVE_TRANZPORT=1;HAVE_WIIMOTE=1;HAVE_LIBS_SURFACES=1;HAVE_2IN2OUT=1;HAVE_1IN2OUT=1;HAVE_VBAP=1;HAVE_LIBS_PANNERS=1;HAVE_LIBS_TIMECODE=1;HAVE_LRDF=1;HAVE_SAMPLERATE=1;HAVE_SERD=1;HAVE_SORD=1;HAVE_SRATOM=1;HAVE_LILV=1;HAVE_LILV_0_16_0=1;HAVE_OGG=1;HAVE_FLAC=1;HAVE_RUBBERBAND=1;USE_RUBBERBAND=1;HAVE_JACK_SESSION=1;HAVE_UNISTD=1;HAVE_JACK_ON_INFO_SHUTDOWN=1;HAVE_JACK_VIDEO_SUPPORT=1;HAVE_BOOST_SCOPED_PTR_HPP=1;HAVE_BOOST_PTR_CONTAINER_PTR_LIST_HPP=1;HAVE_LIBS_ARDOUR=1;HAVE_GTKMM=1;HAVE_GTK=1;HAVE_LIBS_GTKMM2EXT=1;HAVE_LIBS_CLEARLOOKS_NEWER=1;HAVE_BOOST_FORMAT_HPP=1;HAVE_LIBS_AUDIOGRAPHER=1;HAVE_GNOMECANVAS=0;HAVE_GNOMECANVASMM=0;HAVE_X11=0;HAVE_FONTCONFIG=1;HAVE_BOOST_SHARED_PTR_HPP=1;HAVE_BOOST_WEAK_PTR_HPP=1;HAVE_GTK2_ARDOUR=1;HAVE_EXPORT=1;HAVE_MIDI_MAPS=1;HAVE_MCP=1;HAVE_PATCHFILES=1;HAVE_TOOLS_SANITY_CHECK=1;SMF_VERSION=\"1.2\";CURRENT_SESSION_FILE_VERSION=3001"
|
||||
PreprocessorDefinitions="PLATFORM_WINDOWS;DEBUGGABLE_BACKENDS;DEBUGGABLE_SCANNER_APP;COMPILER_MSVC;_SECURE_SCL=0;BUILDING_LIBARDOUR;LIBARDOUR_DLL_EXPORTS;LIBARDOUR=\"mixbus3\";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="\"ardour3\"";PROGRAM_NAME="\"Mixbus\"";PROGRAM_VERSION="\"3\"";_REENTRANT;_USE_MATH_DEFINES;_LARGEFILE_SOURCE;_LARGEFILE64_SOURCE;LIBC_DISABLE_DEPRECATED;BOOST_SYSTEM_NO_DEPRECATED;__STDC_LIMIT_MACROS;__STDC_FORMAT_MACROS;INTERNAL_SHARED_LIBS=1;JACK_SESSION=1;HAVE_GLIB=1;HAVE_GTHREAD=1;HAVE_SNDFILE=1;HAVE_GIOMM=1;HAVE_CURL=1;HAVE_LO=1;HAVE_MODE_T=1;PHONE_HOME=1;FREESOUND=1;WINDOWS_KEY=\"Mod4><Super\";IS_OSX=0;HAVE_XML=1;HAVE_UUID=1;HAVE_LIBS_PBD=1;HAVE_JACK=1;HAVE_LIBS_MIDIPP2=1;HAVE_LIBS_EVORAL=1;HAVE_FFTW3=1;HAVE_FFTW3F=1;HAVE_AUBIO=1;HAVE_LIBS_VAMP_SDK=1;HAVE_LIBS_VAMP_PLUGINS=1;HAVE_LIBS_TAGLIB=1;HAVE_LIBS_LIBLTC=1;HAVE_LIBS_RUBBERBAND=1;HAVE_CONTROL_PROTOCOL=1;HAVE_FRONTIER=1;HAVE_GENERIC_MIDI=1;HAVE_MACKIE=1;HAVE_OSC=1;HAVE_TRANZPORT=1;HAVE_WIIMOTE=1;HAVE_LIBS_SURFACES=1;HAVE_2IN2OUT=1;HAVE_1IN2OUT=1;HAVE_VBAP=1;HAVE_LIBS_PANNERS=1;HAVE_LIBS_TIMECODE=1;HAVE_LRDF=1;HAVE_SAMPLERATE=1;HAVE_SERD=1;HAVE_SORD=1;HAVE_SRATOM=1;HAVE_LILV=1;HAVE_LILV_0_16_0=1;HAVE_OGG=1;HAVE_FLAC=1;HAVE_RUBBERBAND=1;USE_RUBBERBAND=1;HAVE_JACK_SESSION=1;HAVE_UNISTD=1;HAVE_JACK_ON_INFO_SHUTDOWN=1;HAVE_JACK_VIDEO_SUPPORT=1;HAVE_BOOST_SCOPED_PTR_HPP=1;HAVE_BOOST_PTR_CONTAINER_PTR_LIST_HPP=1;HAVE_LIBS_ARDOUR=1;HAVE_GTKMM=1;HAVE_GTK=1;HAVE_LIBS_GTKMM2EXT=1;HAVE_LIBS_CLEARLOOKS_NEWER=1;HAVE_BOOST_FORMAT_HPP=1;HAVE_LIBS_AUDIOGRAPHER=1;HAVE_GNOMECANVAS=0;HAVE_GNOMECANVASMM=0;HAVE_X11=0;HAVE_FONTCONFIG=1;HAVE_BOOST_SHARED_PTR_HPP=1;HAVE_BOOST_WEAK_PTR_HPP=1;HAVE_GTK2_ARDOUR=1;HAVE_EXPORT=1;HAVE_MIDI_MAPS=1;HAVE_MCP=1;HAVE_PATCHFILES=1;HAVE_TOOLS_SANITY_CHECK=1;SMF_VERSION=\"1.2\";CURRENT_SESSION_FILE_VERSION=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"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"); }
|
||||
|
|
|
|||
13
libs/ardour/ardour/lmath.h
Normal file
13
libs/ardour/ardour/lmath.h
Normal 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
|
||||
97
libs/ardour/ardour/midi_channel_filter.h
Normal file
97
libs/ardour/ardour/midi_channel_filter.h
Normal 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__ */
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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*/
|
||||
|
|
|
|||
102
libs/ardour/ardour/note_fixer.h
Normal file
102
libs/ardour/ardour/note_fixer.h
Normal 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__ */
|
||||
|
||||
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 &);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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"); }
|
||||
|
|
|
|||
|
|
@ -456,6 +456,8 @@ namespace ARDOUR {
|
|||
FormatInt16
|
||||
};
|
||||
|
||||
int format_data_width (ARDOUR::SampleFormat);
|
||||
|
||||
enum CDMarkerFormat {
|
||||
CDMarkerNone,
|
||||
CDMarkerCUE,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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). */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
143
libs/ardour/midi_channel_filter.cc
Normal file
143
libs/ardour/midi_channel_filter.cc
Normal 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 */
|
||||
|
|
@ -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 ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue