[SCM] ardour3/upstream: Imported Upstream version 3.5.403~dfsg

adiknoth-guest at users.alioth.debian.org adiknoth-guest at users.alioth.debian.org
Fri Oct 3 11:56:22 UTC 2014


The following commit has been merged in the upstream branch:
commit 72ffa6fae46e3fdcc8fe7f704cb35f70d4c47b46
Author: Adrian Knoth <adi at drcomp.erfurt.thur.de>
Date:   Fri Oct 3 11:59:00 2014 +0200

    Imported Upstream version 3.5.403~dfsg

diff --git a/gtk2_ardour/add_video_dialog.cc b/gtk2_ardour/add_video_dialog.cc
index 57938ac..5464c0a 100644
--- a/gtk2_ardour/add_video_dialog.cc
+++ b/gtk2_ardour/add_video_dialog.cc
@@ -258,7 +258,8 @@ static bool check_video_file_extension(std::string file)
 		".ogg"     , ".OGG"     ,
 		".ogv"     , ".OGV"     ,
 		".mpg"     , ".MPG"     ,
-		".mov"     , ".MOV"     ,
+		".mpeg"    , ".MPEG"    ,
+		".mts"     , ".MTS"    ,
 		".mp4"     , ".MP4"     ,
 		".mkv"     , ".MKV"     ,
 		".vob"     , ".VOB"     ,
@@ -272,6 +273,8 @@ static bool check_video_file_extension(std::string file)
 		".dv"      , ".DV"      ,
 		".dirac"   , ".DIRAC"   ,
 		".webm"    , ".WEBM"    ,
+		".wmv"     , ".wmv"     ,
+		".ts"      , ".ts"      ,
 	};
 
 	for (size_t n = 0; n < sizeof(suffixes)/sizeof(suffixes[0]); ++n) {
diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h
index 3a74fa2..4da4a52 100644
--- a/gtk2_ardour/editor.h
+++ b/gtk2_ardour/editor.h
@@ -1262,7 +1262,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
 			 int target_regions, int target_tracks, boost::shared_ptr<ARDOUR::Track>&, bool add_channel_suffix);
 
 	int finish_bringing_in_material (boost::shared_ptr<ARDOUR::Region> region, uint32_t, uint32_t,  framepos_t& pos, Editing::ImportMode mode,
-				      boost::shared_ptr<ARDOUR::Track>& existing_track);
+					 boost::shared_ptr<ARDOUR::Track>& existing_track, const std::string& new_track_name);
 
 	boost::shared_ptr<ARDOUR::AudioTrack> get_nth_selected_audio_track (int nth) const;
 	boost::shared_ptr<ARDOUR::MidiTrack> get_nth_selected_midi_track (int nth) const;
diff --git a/gtk2_ardour/editor_audio_import.cc b/gtk2_ardour/editor_audio_import.cc
index a19a62b..fb1e101 100644
--- a/gtk2_ardour/editor_audio_import.cc
+++ b/gtk2_ardour/editor_audio_import.cc
@@ -611,7 +611,7 @@ Editor::embed_sndfiles (vector<string> paths, bool multifile,
 
 				boost::shared_ptr<Source> s;
 
-				if ((s = _session->source_by_path_and_channel (path, n)) == 0) {
+				if ((s = _session->audio_source_by_path_and_channel (path, n)) == 0) {
 
 					source = boost::dynamic_pointer_cast<AudioFileSource> (
 						SourceFactory::createExternal (DataType::AUDIO, *_session,
@@ -657,7 +657,8 @@ Editor::add_sources (vector<string> paths, SourceList& sources, framepos_t& pos,
 	uint32_t input_chan = 0;
 	uint32_t output_chan = 0;
 	bool use_timestamp;
-	
+	vector<string> track_names;
+
 	use_timestamp = (pos == -1);
 
 	// kludge (for MIDI we're abusing "channel" for "track" here)
@@ -694,6 +695,11 @@ Editor::add_sources (vector<string> paths, SourceList& sources, framepos_t& pos,
 
 		regions.push_back (r);
 
+		/* if we're creating a new track, name it after the cleaned-up
+		 * and "merged" region name.
+		 */
+
+		track_names.push_back (region_name);
 
 	} else if (target_regions == -1 || target_regions > 1) {
 
@@ -724,29 +730,26 @@ Editor::add_sources (vector<string> paths, SourceList& sources, framepos_t& pos,
 					region_name = (*x)->name();
 				}
 				
-				switch (sources.size()) {
-					/* zero and one channel handled
-					   by previous if() condition
-					*/
-				case 2:
+				if (sources.size() == 2) {
 					if (n == 0) {
 						region_name += "-L";
 					} else {
 						region_name += "-R";
 					}
-					break;
-				default:
-					region_name += (char) '-';
-					region_name += (char) ('1' + n);
-					break;
+				} else if (sources.size() > 2) {
+					region_name += string_compose ("-%1", n+1);
 				}
 				
+				track_names.push_back (region_name);
+				
 			} else {
 				if (fs) {
 					region_name = region_name_from_path (fs->path(), false, false, sources.size(), n);
-				} else{
+				} else {
 					region_name = (*x)->name();
 				}
+
+				track_names.push_back (PBD::basename_nosuffix (paths[n]));
 			}
 
 			PropertyList plist;
@@ -798,6 +801,12 @@ Editor::add_sources (vector<string> paths, SourceList& sources, framepos_t& pos,
 	framepos_t rlen = 0;
 
 	begin_reversible_command (Operations::insert_file);
+
+	/* we only use tracks names when importing to new tracks, but we
+	 * require that one is defined for every region, just to keep
+	 * the API simpler.
+	 */
+	assert (regions.size() == track_names.size());
 	
 	for (vector<boost::shared_ptr<Region> >::iterator r = regions.begin(); r != regions.end(); ++r, ++n) {
 		boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (*r);
@@ -830,9 +839,8 @@ Editor::add_sources (vector<string> paths, SourceList& sources, framepos_t& pos,
                                 pos = get_preferred_edit_position ();
                         }
                 }
-
-
-		finish_bringing_in_material (*r, input_chan, output_chan, pos, mode, track);
+		
+		finish_bringing_in_material (*r, input_chan, output_chan, pos, mode, track, track_names[n]);
 
 		rlen = (*r)->length();
 
@@ -859,7 +867,7 @@ Editor::add_sources (vector<string> paths, SourceList& sources, framepos_t& pos,
 
 int
 Editor::finish_bringing_in_material (boost::shared_ptr<Region> region, uint32_t in_chans, uint32_t out_chans, framepos_t& pos,
-				     ImportMode mode, boost::shared_ptr<Track>& existing_track)
+				     ImportMode mode, boost::shared_ptr<Track>& existing_track, const string& new_track_name)
 {
 	boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
 	boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(region);
@@ -916,7 +924,11 @@ Editor::finish_bringing_in_material (boost::shared_ptr<Region> region, uint32_t
 				existing_track = mt.front();
 			}
 
-			existing_track->set_name (region->name());
+			if (!new_track_name.empty()) {
+				existing_track->set_name (new_track_name);
+			} else {
+				existing_track->set_name (region->name());
+			}
 		}
 
 		boost::shared_ptr<Playlist> playlist = existing_track->playlist();
diff --git a/gtk2_ardour/editor_rulers.cc b/gtk2_ardour/editor_rulers.cc
index 2752f96..ee83d18 100644
--- a/gtk2_ardour/editor_rulers.cc
+++ b/gtk2_ardour/editor_rulers.cc
@@ -1862,13 +1862,13 @@ sample_to_clock_parts ( framepos_t sample,
 	long millisecs;
 
 	left = sample;
-	hrs = left / (sample_rate * 60 * 60);
-	left -= hrs * sample_rate * 60 * 60;
-	mins = left / (sample_rate * 60);
-	left -= mins * sample_rate * 60;
-	secs = left / sample_rate;
-	left -= secs * sample_rate;
-	millisecs = left * 1000 / sample_rate;
+	hrs = left / (sample_rate * 60 * 60 * 1000);
+	left -= hrs * sample_rate * 60 * 60 * 1000;
+	mins = left / (sample_rate * 60 * 1000);
+	left -= mins * sample_rate * 60 * 1000;
+	secs = left / (sample_rate * 1000);
+	left -= secs * sample_rate * 1000;
+	millisecs = left / sample_rate;
 
 	*millisecs_p = millisecs;
 	*secs_p = secs;
@@ -1888,7 +1888,7 @@ Editor::set_minsec_ruler_scale (framepos_t lower, framepos_t upper)
 		return;
 	}
 
-	fr = _session->frame_rate();
+	fr = _session->frame_rate() * 1000;
 
 	/* to prevent 'flashing' */
 	if (lower > (spacer = (framepos_t)(128 * Editor::get_current_zoom ()))) {
@@ -1897,7 +1897,7 @@ Editor::set_minsec_ruler_scale (framepos_t lower, framepos_t upper)
 		lower = 0;
 	}
 	upper += spacer;
-	framecnt_t const range = upper - lower;
+	framecnt_t const range = (upper - lower) * 1000;
 
 	if (range <  (fr / 50)) {
 		minsec_mark_interval =  fr / 1000; /* show 1/1000 seconds */
@@ -1997,7 +1997,7 @@ Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble /*
 	}
 
 	*marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * minsec_nmarks);
-	pos = ((((framepos_t) floor(lower)) + (minsec_mark_interval/2))/minsec_mark_interval) * minsec_mark_interval;
+	pos = (((1000 * (framepos_t) floor(lower)) + (minsec_mark_interval/2))/minsec_mark_interval) * minsec_mark_interval;
 	switch (minsec_ruler_scale) {
 	case minsec_show_seconds:
 		for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) {
@@ -2014,7 +2014,7 @@ Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble /*
 	                        (*marks)[n].style = GtkCustomRulerMarkMicro;
         	        }
                 	(*marks)[n].label = g_strdup (buf);
-              		(*marks)[n].position = pos;
+			(*marks)[n].position = pos/1000.0;
 		}
 	  break;
 	case minsec_show_minutes:
@@ -2032,7 +2032,7 @@ Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble /*
                                 (*marks)[n].style = GtkCustomRulerMarkMicro;
                         }
                         (*marks)[n].label = g_strdup (buf);
-                        (*marks)[n].position = pos;
+                        (*marks)[n].position = pos/1000.0;
                 }
 	  break;
 	case minsec_show_hours:
@@ -2046,14 +2046,14 @@ Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble /*
                                 (*marks)[n].style = GtkCustomRulerMarkMicro;
                         }
                         (*marks)[n].label = g_strdup (buf);
-                        (*marks)[n].position = pos;
+                        (*marks)[n].position = pos/1000.0;
                 }
 	      break;
 	case minsec_show_frames:
 		for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) {
 			sample_to_clock_parts (pos, _session->frame_rate(), &hrs, &mins, &secs, &millisecs);
 			if (millisecs % minsec_mark_modulo == 0) {
-				if (secs == 0) {
+				if (millisecs == 0) {
 					(*marks)[n].style = GtkCustomRulerMarkMajor;
 				} else {
 					(*marks)[n].style = GtkCustomRulerMarkMinor;
@@ -2064,7 +2064,7 @@ Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble /*
 				(*marks)[n].style = GtkCustomRulerMarkMicro;
 			}
 			(*marks)[n].label = g_strdup (buf);
-			(*marks)[n].position = pos;
+			(*marks)[n].position = pos/1000.0;
 		}
 	  break;
 	}
diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc
index aa057d9..ff84ba8 100644
--- a/gtk2_ardour/midi_time_axis.cc
+++ b/gtk2_ardour/midi_time_axis.cc
@@ -757,7 +757,7 @@ MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl
 			Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
 			ctl_items.push_back (
 				CheckMenuElem (
-					string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn)),
+					string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
 					sigc::bind (
 						sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
 						fully_qualified_param)));
@@ -1199,16 +1199,56 @@ MidiTimeAxisView::update_pan_track_visibility ()
 void
 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
 {
+	using namespace MIDI::Name;
+
 	if (apply_to_selection) {
 		_editor.get_selection().tracks.foreach_midi_time_axis (
 			boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
 	} else {
 		if (midi_track()) {
+			// Show existing automation
 			const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
 
 			for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
 				create_automation_child(*i, true);
 			}
+
+			// Show automation for all controllers named in midnam file
+			boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
+			if (gui_property (X_("midnam-model-name")) != "Generic" &&
+			     device_names && !device_names->controls().empty()) {
+				const std::string device_mode       = _midnam_custom_device_mode_selector.get_active_text();
+				const uint16_t    selected_channels = midi_track()->get_playback_channel_mask();
+				for (uint32_t chn = 0; chn < 16; ++chn) {
+					if ((selected_channels & (0x0001 << chn)) == 0) {
+						// Channel not in use
+						continue;
+					}
+
+					boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
+						device_mode, chn);
+					if (!chan_names) {
+						continue;
+					}
+
+					boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
+						chan_names->control_list_name());
+					if (!control_names) {
+						continue;
+					}
+
+					for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
+					     c != control_names->controls().end();
+					     ++c) {
+						const uint16_t ctl = c->second->number();
+						if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
+							/* Skip bank select controllers since they're handled specially */
+							const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
+							create_automation_child(param, true);
+						}
+					}
+				}
+			}
 		}
 
 		RouteTimeAxisView::show_all_automation ();
diff --git a/gtk2_ardour/mnemonic-us.bindings.in b/gtk2_ardour/mnemonic-us.bindings.in
index d0bc802..9b4479a 100644
--- a/gtk2_ardour/mnemonic-us.bindings.in
+++ b/gtk2_ardour/mnemonic-us.bindings.in
@@ -339,7 +339,7 @@ This mode provides many different operations on both regions and control points,
 @trans|Transport/ToggleAutoPlay|5|toggle auto play
 @trans|Transport/ToggleAutoReturn|6|toggle auto return
 @trans|Transport/ToggleClick|7|toggle click (metronome)
- at ranges|Editor/set-tempo-from-region|9|set tempo (1 bar) from region(s)
+ at ranges|Region/set-tempo-from-region|9|set tempo (1 bar) from region(s)
 @ranges|Editor/set-tempo-from-edit-range|0|set tempo (1 bar) from edit range
 
 ; mouse stuff
diff --git a/gtk2_ardour/video_timeline.cc b/gtk2_ardour/video_timeline.cc
index 33331db..fd6a6f8 100644
--- a/gtk2_ardour/video_timeline.cc
+++ b/gtk2_ardour/video_timeline.cc
@@ -39,6 +39,10 @@
 #include <pthread.h>
 #include <curl/curl.h>
 
+#ifdef PLATFORM_WINDOWS
+#include <windows.h>
+#endif
+
 #include "i18n.h"
 
 using namespace std;
@@ -718,20 +722,45 @@ void
 VideoTimeLine::find_xjadeo () {
 	std::string xjadeo_file_path;
 	if (getenv("XJREMOTE")) {
-		_xjadeo_bin = strdup(getenv("XJREMOTE")); // XXX TODO: free it?!
-	} else if (find_file_in_search_path (SearchPath(Glib::getenv("PATH")), X_("xjremote"), xjadeo_file_path)) {
+		_xjadeo_bin = getenv("XJREMOTE");
+	}
+	else if (find_file_in_search_path (SearchPath(Glib::getenv("PATH")), X_("xjremote"), xjadeo_file_path)) {
 		_xjadeo_bin = xjadeo_file_path;
 	}
+	else if (find_file_in_search_path (SearchPath(Glib::getenv("PATH")), X_("xjadeo"), xjadeo_file_path)) {
+		_xjadeo_bin = xjadeo_file_path;
+	}
+#ifdef __APPLE__
+	else if (Glib::file_test(X_("/Applications/Xjadeo.app/Contents/MacOS/xjremote"), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_EXECUTABLE)) {
+		_xjadeo_bin = X_("/Applications/Xjadeo.app/Contents/MacOS/xjremote");
+	}
 	else if (Glib::file_test(X_("/Applications/Jadeo.app/Contents/MacOS/xjremote"), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_EXECUTABLE)) {
 		_xjadeo_bin = X_("/Applications/Jadeo.app/Contents/MacOS/xjremote");
 	}
-	/* TODO: win32: allow to configure PATH to xjremote */
+#endif
+#ifdef PLATFORM_WINDOWS
+	else {
+		HKEY key;
+		DWORD size = PATH_MAX;
+		char path[PATH_MAX+1];
+		xjadeo_file_path = X_("");
+		if (   (ERROR_SUCCESS == RegOpenKeyExA (HKEY_LOCAL_MACHINE, "Software\\RSS\\xjadeo", 0, KEY_READ, &key))
+		    && (ERROR_SUCCESS == RegQueryValueExA (key, "Install_Dir", 0, NULL, (LPBYTE)path, &size))
+		   )
+		{
+			xjadeo_file_path = g_build_filename(path, X_("xjadeo.exe"));
+		}
+	}
+	if (Glib::file_test(xjadeo_file_path, Glib::FILE_TEST_EXISTS)) {
+		_xjadeo_bin = xjadeo_file_path;
+	}
 	else if (Glib::file_test(X_("C:\\Program Files\\xjadeo\\xjremote.exe"), Glib::FILE_TEST_EXISTS)) {
 		_xjadeo_bin = X_("C:\\Program Files\\xjadeo\\xjremote.exe");
 	}
 	else if (Glib::file_test(X_("C:\\Program Files\\xjadeo\\xjremote.bat"), Glib::FILE_TEST_EXISTS)) {
 		_xjadeo_bin = X_("C:\\Program Files\\xjadeo\\xjremote.bat");
 	}
+#endif
 	else  {
 		_xjadeo_bin = X_("");
 		warning << _("Video-monitor 'xjadeo' was not found. Please install http://xjadeo.sf.net/ "
diff --git a/libs/ardour/ardour/audiofilesource.h b/libs/ardour/ardour/audiofilesource.h
index 9be8d6c..7f4b18e 100644
--- a/libs/ardour/ardour/audiofilesource.h
+++ b/libs/ardour/ardour/audiofilesource.h
@@ -93,6 +93,12 @@ protected:
 	/** Constructor to be called for existing in-session files */
 	AudioFileSource (Session&, const XMLNode&, bool must_exist = true);
 
+	/** Constructor to be called for crash recovery. Final argument is not
+	 * used but exists to differentiate from the external-to-session
+	 * constructor above.
+	 */
+	AudioFileSource (Session&, const std::string& path, Source::Flag flags, bool);
+
 	int init (const std::string& idstr, bool must_exist);
 
 	virtual void set_header_timeline_position () = 0;
diff --git a/libs/ardour/ardour/file_source.h b/libs/ardour/ardour/file_source.h
index 531cdf4..8eebfea 100644
--- a/libs/ardour/ardour/file_source.h
+++ b/libs/ardour/ardour/file_source.h
@@ -85,6 +85,10 @@ public:
 	void existence_check ();
 	virtual void prevent_deletion ();
 
+	/** Rename the file on disk referenced by this source to \param newname
+	 */
+	int rename (const std::string& name);
+
 protected:
 	FileSource (Session& session, DataType type,
 	            const std::string& path,
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 38185a7..b93f932 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -195,10 +195,10 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
 	std::string peak_path (std::string) const;
 
 	std::string peak_path_from_audio_path (std::string) const;
-	std::string new_audio_source_name (const std::string&, uint32_t nchans, uint32_t chan, bool destructive);
-	std::string new_midi_source_name (const std::string&);
-	std::string new_source_path_from_name (DataType type, const std::string&);
+	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);
+	std::vector<std::string> get_paths_for_new_sources (bool allow_replacing, const std::string& import_file_path, uint32_t channels);
 
 	void process (pframes_t nframes);
 
@@ -526,8 +526,6 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
 
 	boost::shared_ptr<Region> find_whole_file_parent (boost::shared_ptr<Region const>) const;
 
-	std::string path_from_region_name (DataType type, std::string name, std::string identifier);
-
 	boost::shared_ptr<Region>      XMLRegionFactory (const XMLNode&, bool full);
 	boost::shared_ptr<AudioRegion> XMLAudioRegionFactory (const XMLNode&, bool full);
 	boost::shared_ptr<MidiRegion>  XMLMidiRegionFactory (const XMLNode&, bool full);
@@ -584,8 +582,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
 	boost::shared_ptr<MidiSource> create_midi_source_by_stealing_name (boost::shared_ptr<Track>);
 
 	boost::shared_ptr<Source> source_by_id (const PBD::ID&);
-	boost::shared_ptr<AudioFileSource> source_by_path_and_channel (const std::string&, uint16_t) const;
-	boost::shared_ptr<MidiSource> source_by_path (const std::string&) const;
+	boost::shared_ptr<AudioFileSource> audio_source_by_path_and_channel (const std::string&, uint16_t) const;
+	boost::shared_ptr<MidiSource> midi_source_by_path (const std::string&) const;
 	uint32_t count_sources_by_origin (const std::string&);
 
 	void add_playlist (boost::shared_ptr<Playlist>, bool unused = false);
@@ -1433,7 +1431,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
 
 	bool no_questions_about_missing_files;
 
-	std::string get_best_session_directory_for_new_source ();
+	std::string get_best_session_directory_for_new_audio ();
 
 	mutable gint _playback_load;
 	mutable gint _capture_load;
diff --git a/libs/ardour/ardour/smf_source.h b/libs/ardour/ardour/smf_source.h
index a068a3e..f359100 100644
--- a/libs/ardour/ardour/smf_source.h
+++ b/libs/ardour/ardour/smf_source.h
@@ -47,15 +47,6 @@ public:
 
 	virtual ~SMFSource ();
 
-	/** Rename the file on disk referenced by this source to \param newname
-	 *
-	 * This method exists only for MIDI file sources, not for audio, which 
-	 * can never be renamed. It exists for MIDI so that we can get
-	 * consistent and sane region/source numbering when regions are added
-	 * manually (which never happens with audio).
-	 */
-	int rename (const std::string& name);
-
         bool safe_file_extension (const std::string& path) const {
 		return safe_midi_file_extension(path);
 	}
diff --git a/libs/ardour/ardour/sndfilesource.h b/libs/ardour/ardour/sndfilesource.h
index 3f63f1c..9604d3f 100644
--- a/libs/ardour/ardour/sndfilesource.h
+++ b/libs/ardour/ardour/sndfilesource.h
@@ -38,7 +38,16 @@ class SndFileSource : public AudioFileSource {
 	               SampleFormat samp_format, HeaderFormat hdr_format, framecnt_t rate,
 	               Flag flags = SndFileSource::default_writable_flags);
 
-	/** Constructor to be called for existing in-session files */
+	/* Constructor to be called for recovering files being used for
+	 * capture. They are in-session, they already exist, they should not
+	 * be writable. They are an odd hybrid (from a constructor point of
+	 * view) of the previous two constructors.
+	 */
+	SndFileSource (Session&, const std::string& path, int chn);
+
+	/** Constructor to be called for existing in-session files during
+	 * session loading 
+	 */
 	SndFileSource (Session&, const XMLNode&);
 
 	~SndFileSource ();
diff --git a/libs/ardour/ardour/source.h b/libs/ardour/ardour/source.h
index 5e85170..4427d65 100644
--- a/libs/ardour/ardour/source.h
+++ b/libs/ardour/ardour/source.h
@@ -47,7 +47,8 @@ class Source : public SessionObject
 		RemovableIfEmpty = 0x10,
 		RemoveAtDestroy = 0x20,
 		NoPeakFile = 0x40,
-		Destructive = 0x80
+		Destructive = 0x80,
+		Empty = 0x100, /* used for MIDI only */
 	};
 
 	Source (Session&, DataType type, const std::string& name, Flag flags=Flag(0));
diff --git a/libs/ardour/ardour/source_factory.h b/libs/ardour/ardour/source_factory.h
index c94f783..ce0f86b 100644
--- a/libs/ardour/ardour/source_factory.h
+++ b/libs/ardour/ardour/source_factory.h
@@ -57,6 +57,9 @@ class SourceFactory {
 		 bool destructive, framecnt_t rate, bool announce = true, bool async = false);
 
 
+	static boost::shared_ptr<Source> createForRecovery
+		(DataType type, Session&, const std::string& path, int chn);
+
 	static boost::shared_ptr<Source> createFromPlaylist
 		(DataType type, Session& s, boost::shared_ptr<Playlist> p, const PBD::ID& orig, const std::string& name,
 		 uint32_t chn, frameoffset_t start, framecnt_t len, bool copy, bool defer_peaks);
diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc
index 010e1da..7785284 100644
--- a/libs/ardour/audio_diskstream.cc
+++ b/libs/ardour/audio_diskstream.cc
@@ -2181,11 +2181,16 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
 				continue;
 			}
 
+			/* XXX as of June 2014, we always record to mono
+			   files. Since this Source is being created as part of
+			   crash recovery, we know that we need the first
+			   channel (the final argument to the SourceFactory
+			   call below). If we ever support non-mono files for
+			   capture, this will need rethinking.
+			*/
+
 			try {
-				fs = boost::dynamic_pointer_cast<AudioFileSource> (
-					SourceFactory::createWritable (
-						DataType::AUDIO, _session,
-						prop->value(), false, _session.frame_rate()));
+				fs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createForRecovery (DataType::AUDIO, _session, prop->value(), 0));
 			}
 
 			catch (failed_constructor& err) {
@@ -2216,21 +2221,31 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
 		return -1;
 	}
 
-	boost::shared_ptr<AudioRegion> region;
-
 	try {
 
-		PropertyList plist;
+		boost::shared_ptr<AudioRegion> wf_region;
+		boost::shared_ptr<AudioRegion> region;
+		
+		/* First create the whole file region */
 
+		PropertyList plist;
+		
 		plist.add (Properties::start, 0);
 		plist.add (Properties::length, first_fs->length (first_fs->timeline_position()));
 		plist.add (Properties::name, region_name_from_path (first_fs->name(), true));
 
-		region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (pending_sources, plist));
+		wf_region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (pending_sources, plist));
+
+		wf_region->set_automatic (true);
+		wf_region->set_whole_file (true);
+		wf_region->special_set_position (position);
 
-		region->set_automatic (true);
-		region->set_whole_file (true);
-		region->special_set_position (0);
+		/* Now create a region that isn't the whole file for adding to
+		 * the playlist */
+
+		region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (pending_sources, plist));
+		
+		_playlist->add_region (region, position);
 	}
 
 	catch (failed_constructor& err) {
@@ -2241,7 +2256,6 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
 		return -1;
 	}
 
-	_playlist->add_region (region, position);
 
 	return 0;
 }
diff --git a/libs/ardour/audiofilesource.cc b/libs/ardour/audiofilesource.cc
index 13b03f8..8c3bf00 100644
--- a/libs/ardour/audiofilesource.cc
+++ b/libs/ardour/audiofilesource.cc
@@ -36,6 +36,7 @@
 #include "pbd/stl_delete.h"
 #include "pbd/strsplit.h"
 #include "pbd/shortpath.h"
+#include "pbd/stacktrace.h"
 #include "pbd/enumwriter.h"
 
 #include <sndfile.h>
@@ -114,6 +115,22 @@ AudioFileSource::AudioFileSource (Session& s, const string& path, const string&
 	}
 }
 
+/** Constructor used for existing internal-to-session files during crash
+ * recovery. File must exist
+ */
+AudioFileSource::AudioFileSource (Session& s, const string& path, Source::Flag flags, bool /* ignored-exists-for-prototype differentiation */)
+	: Source (s, DataType::AUDIO, path, flags)
+	, AudioSource (s, path)
+	, FileSource (s, DataType::AUDIO, path, string(), flags)
+{
+        /* note that origin remains empty */
+
+	if (init (_path, true)) {
+		throw failed_constructor ();
+	}
+}
+
+
 /** Constructor used for existing internal-to-session files via XML.  File must exist. */
 AudioFileSource::AudioFileSource (Session& s, const XMLNode& node, bool must_exist)
 	: Source (s, node)
diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc
index a359f22..94b6847 100644
--- a/libs/ardour/diskstream.cc
+++ b/libs/ardour/diskstream.cc
@@ -739,4 +739,3 @@ Diskstream::disengage_record_enable ()
 {
 	g_atomic_int_set (&_record_enabled, 0);
 }
-
diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc
index e32fe32..142ce2c 100644
--- a/libs/ardour/enums.cc
+++ b/libs/ardour/enums.cc
@@ -447,6 +447,7 @@ setup_enum_writer ()
 	REGISTER_CLASS_ENUM (Source, RemoveAtDestroy);
 	REGISTER_CLASS_ENUM (Source, NoPeakFile);
 	REGISTER_CLASS_ENUM (Source, Destructive);
+	REGISTER_CLASS_ENUM (Source, Empty);
 	REGISTER_BITS (_Source_Flag);
 
 	REGISTER_ENUM (FadeLinear);
diff --git a/libs/ardour/file_source.cc b/libs/ardour/file_source.cc
index de2783a..5833d29 100644
--- a/libs/ardour/file_source.cc
+++ b/libs/ardour/file_source.cc
@@ -56,7 +56,7 @@ PBD::Signal3<int,std::string,std::string,std::vector<std::string> > FileSource::
 FileSource::FileSource (Session& session, DataType type, const string& path, const string& origin, Source::Flag flag)
 	: Source(session, type, path, flag)
 	, _path (path)
-	, _file_is_new (!origin.empty()) // origin empty => new file VS. origin !empty => new file
+	, _file_is_new (!origin.empty()) // if origin is left unspecified (empty string) then file must exist
 	, _channel (0)
         , _origin (origin)
         , _open (false)
@@ -214,7 +214,7 @@ FileSource::move_to_trash (const string& trash_dir_name)
 
 	if (move_dependents_to_trash() != 0) {
 		/* try to back out */
-		rename (newpath.c_str(), _path.c_str());
+		::rename (newpath.c_str(), _path.c_str());
 		return -1;
 	}
 
@@ -256,8 +256,6 @@ FileSource::find (Session& s, DataType type, const string& path, bool must_exist
 
                 split (search_path, dirs, ':');
 
-                hits.clear ();
-
                 for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
 
                         fullpath = Glib::build_filename (*i, path);
@@ -312,9 +310,9 @@ FileSource::find (Session& s, DataType type, const string& path, bool must_exist
 			/* no match: error */
 
                         if (must_exist) {
-                                error << string_compose(
-                                        _("Filesource: cannot find required file (%1): while searching %2"),
-                                        path, search_path) << endmsg;
+				/* do not generate an error here, leave that to
+				   whoever deals with the false return value.
+				*/
                                 goto out;
                         } else {
                                 isnew = true;
@@ -325,16 +323,17 @@ FileSource::find (Session& s, DataType type, const string& path, bool must_exist
 			
 			keeppath = de_duped_hits[0];
 		}
-						  
-        } else {
+						   
+       } else {
                 keeppath = path;
         }
 
         /* Current find() is unable to parse relative path names to yet non-existant
            sources. QuickFix(tm)
         */
-        if (keeppath == "") {
-                if (must_exist) {
+
+	if (keeppath.empty()) {
+		if (must_exist) {
                         error << "FileSource::find(), keeppath = \"\", but the file must exist" << endl;
                 } else {
                         keeppath = path;
@@ -581,3 +580,28 @@ FileSource::is_stub () const
 	return true;
 }
 		
+int
+FileSource::rename (const string& newpath)
+{
+	Glib::Threads::Mutex::Lock lm (_lock);
+	string oldpath = _path;
+
+	// Test whether newpath exists, if yes notify the user but continue.
+	if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
+		error << string_compose (_("Programming error! %1 tried to rename a file over another file! It's safe to continue working, but please report this to the developers."), PROGRAM_NAME) << endmsg;
+		return -1;
+	}
+
+	if (Glib::file_test (oldpath.c_str(), Glib::FILE_TEST_EXISTS)) { 
+		/* rename only needed if file exists on disk */
+		if (::rename (oldpath.c_str(), newpath.c_str()) != 0) {
+			error << string_compose (_("cannot rename file %1 to %2 (%3)"), oldpath, newpath, strerror(errno)) << endmsg;
+			return -1;
+		}
+	}
+
+	_name = Glib::path_get_basename (newpath);
+	_path = newpath;
+
+	return 0;
+}
diff --git a/libs/ardour/filter.cc b/libs/ardour/filter.cc
index b085ec9..b723de1 100644
--- a/libs/ardour/filter.cc
+++ b/libs/ardour/filter.cc
@@ -59,10 +59,9 @@ Filter::make_new_sources (boost::shared_ptr<Region> region, SourceList& nsrcs, s
 			}
 		}
 
-		string path = session.path_from_region_name (region->data_type(),
-				PBD::basename_nosuffix (names[i]), string (""));
+		string path = session.new_audio_source_path (name, region->n_channels(), i, false, false);
 
-		if (path.length() == 0) {
+		if (path.empty()) {
 			error << string_compose (_("filter: error creating name for new file based on %1"), region->name())
 			      << endmsg;
 			return -1;
diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc
index 047b46f..6f7b3d0 100644
--- a/libs/ardour/import.cc
+++ b/libs/ardour/import.cc
@@ -116,78 +116,31 @@ open_importable_source (const string& path, framecnt_t samplerate, ARDOUR::SrcQu
 	}
 }
 
-static std::string
-get_non_existent_filename (HeaderFormat hf, DataType type, const bool allow_replacing, const std::string& destdir, const std::string& basename, uint channel, uint channels)
-{
-	char buf[PATH_MAX+1];
-	bool goodfile = false;
-	string base = basename;
-	string ext = native_header_format_extension (hf, type);
-	uint32_t cnt = 1;
-
-	do {
-
-		if (type == DataType::AUDIO && channels == 2) {
-			if (channel == 0) {
-				if (cnt == 1) {
-					snprintf (buf, sizeof(buf), "%s-L%s", base.c_str(), ext.c_str());
-				} else {
-					snprintf (buf, sizeof(buf), "%s-%d-L%s", base.c_str(), cnt, ext.c_str());
-				}
-			} else {
-				if (cnt == 1) {
-					snprintf (buf, sizeof(buf), "%s-R%s", base.c_str(), ext.c_str());
-				} else {
-					snprintf (buf, sizeof(buf), "%s-%d-R%s", base.c_str(), cnt, ext.c_str());
-				}
-			}
-		} else if (channels > 1) {
-			if (cnt == 1) {
-				snprintf (buf, sizeof(buf), "%s-c%d%s", base.c_str(), channel, ext.c_str());
-			} else {
-				snprintf (buf, sizeof(buf), "%s-%d-c%d%s", base.c_str(), cnt, channel, ext.c_str());
-			}
-		} else {
-			if (cnt == 1) {
-				snprintf (buf, sizeof(buf), "%s%s", base.c_str(), ext.c_str());
-			} else {
-				snprintf (buf, sizeof(buf), "%s-%d%s", base.c_str(), cnt, ext.c_str());
-			}
-		}
-
-		string tempname = destdir + "/" + buf;
-
-		if (!allow_replacing && Glib::file_test (tempname, Glib::FILE_TEST_EXISTS)) {
-
-			cnt++;
-
-		} else {
-
-			goodfile = true;
-		}
-
-	} while (!goodfile);
-
-	return buf;
-}
-
-static vector<string>
-get_paths_for_new_sources (HeaderFormat hf, const bool allow_replacing, const string& import_file_path, const string& session_dir, uint channels)
+vector<string>
+Session::get_paths_for_new_sources (bool /*allow_replacing*/, const string& import_file_path, uint32_t channels)
 {
 	vector<string> new_paths;
 	const string basename = basename_nosuffix (import_file_path);
 
-	SessionDirectory sdir(session_dir);
-
 	for (uint n = 0; n < channels; ++n) {
 
 		const DataType type = SMFSource::safe_midi_file_extension (import_file_path) ? DataType::MIDI : DataType::AUDIO;
+		string filepath;
+
+		switch (type) {
+		  case DataType::MIDI:
+			filepath = new_midi_source_path (basename);
+			break;
+		case DataType::AUDIO:
+			filepath = new_audio_source_path (basename, channels, n, false, false);
+			break;
+		}
 
-		std::string filepath = (type == DataType::MIDI)
-			? sdir.midi_path() : sdir.sound_path();
+		if (filepath.empty()) {
+			error << string_compose (_("Cannot find new filename for imported file %1"), import_file_path) << endmsg;
+			return vector<string>();
+		}
 
-		filepath = Glib::build_filename (filepath,
-		                                 get_non_existent_filename (hf, type, allow_replacing, filepath, basename, n, channels));
 		new_paths.push_back (filepath);
 	}
 
@@ -201,7 +154,7 @@ map_existing_mono_sources (const vector<string>& new_paths, Session& /*sess*/,
 	for (vector<string>::const_iterator i = new_paths.begin();
 	     i != new_paths.end(); ++i)
 	{
-		boost::shared_ptr<Source> source = session->source_by_path_and_channel(*i, 0);
+		boost::shared_ptr<Source> source = session->audio_source_by_path_and_channel(*i, 0);
 
 		if (source == 0) {
 			error << string_compose(_("Could not find a source for %1 even though we are updating this file!"), (*i)) << endl;
@@ -274,12 +227,12 @@ write_audio_data_to_new_files (ImportableSource* source, ImportStatus& status,
 {
 	const framecnt_t nframes = ResampledImportableSource::blocksize;
 	boost::shared_ptr<AudioFileSource> afs;
-	uint channels = source->channels();
+	uint32_t channels = source->channels();
 
 	boost::scoped_array<float> data(new float[nframes * channels]);
 	vector<boost::shared_array<Sample> > channel_data;
 
-	for (uint n = 0; n < channels; ++n) {
+	for (uint32_t n = 0; n < channels; ++n) {
 		channel_data.push_back(boost::shared_array<Sample>(new Sample[nframes]));
 	}
 
@@ -323,14 +276,14 @@ write_audio_data_to_new_files (ImportableSource* source, ImportStatus& status,
 		progress_multiplier = 0.5;
 		progress_base = 0.5;
 	}
-
-	uint read_count = 0;
+	
+	framecnt_t read_count = 0;
 
 	while (!status.cancel) {
 
 		framecnt_t nread, nfread;
-		uint x;
-		uint chn;
+		uint32_t x;
+		uint32_t chn;
 
 		if ((nread = source->read (data.get(), nframes)) == 0) {
 			break;
@@ -513,10 +466,7 @@ Session::import_files (ImportStatus& status)
 			}
 		}
 
-		vector<string> new_paths = get_paths_for_new_sources (config.get_native_file_header_format(),
-		                                                      status.replace_existing_source, *p,
-		                                                      get_best_session_directory_for_new_source (),
-		                                                      channels);
+		vector<string> new_paths = get_paths_for_new_sources (status.replace_existing_source, *p, channels);
 		Sources newfiles;
 		framepos_t natural_position = source ? source->natural_position() : 0;
 
diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc
index c38c08d..54b0602 100644
--- a/libs/ardour/midi_diskstream.cc
+++ b/libs/ardour/midi_diskstream.cc
@@ -1234,9 +1234,9 @@ MidiDiskstream::steal_write_source_name ()
 	 */
 
 	try {
-		string new_name = _session.new_midi_source_name (name());
+		string new_path = _session.new_midi_source_path (name());
 		
-		if (_write_source->rename (new_name)) {
+		if (_write_source->rename (new_path)) {
 			return string();
 		}
 	} catch (...) {
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 1de5730..dd0cbc6 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -36,6 +36,7 @@
 
 #include <boost/algorithm/string/erase.hpp>
 
+#include "pbd/convert.h"
 #include "pbd/error.h"
 #include "pbd/boost_debug.h"
 #include "pbd/pathscanner.h"
@@ -3305,7 +3306,7 @@ Session::source_by_id (const PBD::ID& id)
 }
 
 boost::shared_ptr<AudioFileSource>
-Session::source_by_path_and_channel (const string& path, uint16_t chn) const
+Session::audio_source_by_path_and_channel (const string& path, uint16_t chn) const
 {
 	/* Restricted to audio files because only audio sources have channel
 	   as a property.
@@ -3326,7 +3327,7 @@ Session::source_by_path_and_channel (const string& path, uint16_t chn) const
 }
 
 boost::shared_ptr<MidiSource>
-Session::source_by_path (const std::string& path) const
+Session::midi_source_by_path (const std::string& path) const
 {
 	/* Restricted to MIDI files because audio sources require a channel
 	   for unique identification, in addition to a path.
@@ -3366,30 +3367,6 @@ Session::count_sources_by_origin (const string& path)
 	return cnt;
 }
 
-/** Return the full path (in some session directory) for a new within-session source.
- * \a name must be a session-unique name that does not contain slashes
- *         (e.g. as returned by new_*_source_name)
- */
-string
-Session::new_source_path_from_name (DataType type, const string& name)
-{
-	assert(name.find("/") == string::npos);
-
-	SessionDirectory sdir(get_best_session_directory_for_new_source());
-
-	std::string p;
-	if (type == DataType::AUDIO) {
-		p = sdir.sound_path();
-	} else if (type == DataType::MIDI) {
-		p = sdir.midi_path();
-	} else {
-		error << "Unknown source type, unable to create file path" << endmsg;
-		return "";
-	}
-
-	return Glib::build_filename (p, name);
-}
-
 string
 Session::peak_path (string base) const
 {
@@ -3398,18 +3375,20 @@ Session::peak_path (string base) const
 
 /** Return a unique name based on \a base for a new internal audio source */
 string
-Session::new_audio_source_name (const string& base, uint32_t nchan, uint32_t chan, bool destructive)
+Session::new_audio_source_path (const string& base, uint32_t nchan, uint32_t chan, bool destructive, bool take_required)
 {
 	uint32_t cnt;
-	char buf[PATH_MAX+1];
-	const uint32_t limit = 10000;
+	string possible_name;
+	const uint32_t limit = 9999; // arbitrary limit on number of files with the same basic name
 	string legalized;
 	string ext = native_header_format_extension (config.get_native_file_header_format(), DataType::AUDIO);
+	bool some_related_source_name_exists = false;
 
-	buf[0] = '\0';
+	possible_name[0] = '\0';
 	legalized = legalize_for_path (base);
 
 	// Find a "version" of the base name that doesn't exist in any of the possible directories.
+
 	for (cnt = (destructive ? ++destructive_index : 1); cnt <= limit; ++cnt) {
 
 		vector<space_and_path>::iterator i;
@@ -3417,47 +3396,37 @@ Session::new_audio_source_name (const string& base, uint32_t nchan, uint32_t cha
 
 		for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
 
-			if (destructive) {
-
-				if (nchan < 2) {
-					snprintf (buf, sizeof(buf), "T%04d-%s%s",
-					          cnt, legalized.c_str(), ext.c_str());
-				} else if (nchan == 2) {
-					if (chan == 0) {
-						snprintf (buf, sizeof(buf), "T%04d-%s%%L%s",
-						          cnt, legalized.c_str(), ext.c_str());
-					} else {
-						snprintf (buf, sizeof(buf), "T%04d-%s%%R%s",
-						          cnt, legalized.c_str(), ext.c_str());
-					}
-				} else if (nchan < 26) {
-					snprintf (buf, sizeof(buf), "T%04d-%s%%%c%s",
-					          cnt, legalized.c_str(), 'a' + chan, ext.c_str());
-				} else {
-					snprintf (buf, sizeof(buf), "T%04d-%s%s",
-					          cnt, legalized.c_str(), ext.c_str());
-				}
+			ostringstream sstr;
 
+			if (destructive) {
+				sstr << 'T';
+				sstr << setfill ('0') << setw (4) << cnt;
+				sstr << legalized;
 			} else {
-
-				if (nchan < 2) {
-					snprintf (buf, sizeof(buf), "%s-%u%s", legalized.c_str(), cnt, ext.c_str());
-				} else if (nchan == 2) {
-					if (chan == 0) {
-						snprintf (buf, sizeof(buf), "%s-%u%%L%s", legalized.c_str(), cnt, ext.c_str());
-					} else {
-						snprintf (buf, sizeof(buf), "%s-%u%%R%s", legalized.c_str(), cnt, ext.c_str());
-					}
-				} else if (nchan < 26) {
-					snprintf (buf, sizeof(buf), "%s-%u%%%c%s", legalized.c_str(), cnt, 'a' + chan, ext.c_str());
-				} else {
-					snprintf (buf, sizeof(buf), "%s-%u%s", legalized.c_str(), cnt, ext.c_str());
+				sstr << legalized;
+				
+				if (take_required || some_related_source_name_exists) {
+					sstr << '-';
+					sstr << cnt;
 				}
 			}
+			
+			if (nchan == 2) {
+				if (chan == 0) {
+					sstr << "%L";
+				} else {
+					sstr << "%R";
+				}
+			} else if (nchan > 2 && nchan < 26) {
+				sstr << '%';
+				sstr << 'a' + chan;
+			} 
 
-			SessionDirectory sdir((*i).path);
+			sstr << ext;
 
-			string spath = sdir.sound_path();
+			possible_name = sstr.str();
+			SessionDirectory sdir((*i).path);
+			const string spath = sdir.sound_path();
 
 			/* note that we search *without* the extension so that
 			   we don't end up both "Audio 1-1.wav" and "Audio 1-1.caf"
@@ -3465,7 +3434,7 @@ Session::new_audio_source_name (const string& base, uint32_t nchan, uint32_t cha
 			   a file format change.
 			*/
 
-			if (matching_unsuffixed_filename_exists_in (spath, buf)) {
+			if (matching_unsuffixed_filename_exists_in (spath, possible_name)) {
 				existing++;
 				break;
 			}
@@ -3479,9 +3448,9 @@ Session::new_audio_source_name (const string& base, uint32_t nchan, uint32_t cha
 			 * notions of their removability.
 			 */
 
-			string possible_path = Glib::build_filename (spath, buf);
+			string possible_path = Glib::build_filename (spath, possible_name);
 
-			if (source_by_path (possible_path)) {
+			if (audio_source_by_path_and_channel (possible_path, chan)) {
 				existing++;
 				break;
 			}
@@ -3491,6 +3460,8 @@ Session::new_audio_source_name (const string& base, uint32_t nchan, uint32_t cha
 			break;
 		}
 
+		some_related_source_name_exists = true;
+
 		if (cnt > limit) {
 			error << string_compose(
 					_("There are already %1 recordings for %2, which I consider too many."),
@@ -3500,32 +3471,31 @@ Session::new_audio_source_name (const string& base, uint32_t nchan, uint32_t cha
 		}
 	}
 
-	return Glib::path_get_basename (buf);
-}
+	/* We've established that the new name does not exist in any session
+	 * directory, so now find out which one we should use for this new
+	 * audio source.
+	 */
 
-/** Create a new within-session audio source */
-boost::shared_ptr<AudioFileSource>
-Session::create_audio_source_for_session (size_t n_chans, string const & n, uint32_t chan, bool destructive)
-{
-	const string name    = new_audio_source_name (n, n_chans, chan, destructive);
-	const string path    = new_source_path_from_name(DataType::AUDIO, name);
+	SessionDirectory sdir (get_best_session_directory_for_new_audio());
 
-	return boost::dynamic_pointer_cast<AudioFileSource> (
-		SourceFactory::createWritable (DataType::AUDIO, *this, path, destructive, frame_rate()));
+	std::string s = Glib::build_filename (sdir.sound_path(), possible_name);
+
+	return s;
 }
 
 /** Return a unique name based on \a owner_name for a new internal MIDI source */
 string
-Session::new_midi_source_name (const string& owner_name)
+Session::new_midi_source_path (const string& base)
 {
 	uint32_t cnt;
 	char buf[PATH_MAX+1];
 	const uint32_t limit = 10000;
 	string legalized;
+	string possible_path;
 	string possible_name;
 
 	buf[0] = '\0';
-	legalized = legalize_for_path (owner_name);
+	legalized = legalize_for_path (base);
 
 	// Find a "version" of the file name that doesn't exist in any of the possible directories.
 
@@ -3533,7 +3503,7 @@ Session::new_midi_source_name (const string& owner_name)
 
 		vector<space_and_path>::iterator i;
 		uint32_t existing = 0;
-
+		
 		for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
 
 			SessionDirectory sdir((*i).path);
@@ -3541,13 +3511,13 @@ Session::new_midi_source_name (const string& owner_name)
 			snprintf (buf, sizeof(buf), "%s-%u.mid", legalized.c_str(), cnt);
 			possible_name = buf;
 
-			std::string possible_path = Glib::build_filename (sdir.midi_path(), possible_name);
+			possible_path = Glib::build_filename (sdir.midi_path(), possible_name);
 			
 			if (Glib::file_test (possible_path, Glib::FILE_TEST_EXISTS)) {
 				existing++;
 			}
 
-			if (source_by_path (possible_path)) {
+			if (midi_source_by_path (possible_path)) {
 				existing++;
 			}
 		}
@@ -3559,31 +3529,47 @@ Session::new_midi_source_name (const string& owner_name)
 		if (cnt > limit) {
 			error << string_compose(
 					_("There are already %1 recordings for %2, which I consider too many."),
-					limit, owner_name) << endmsg;
+					limit, base) << endmsg;
 			destroy ();
-			throw failed_constructor();
+			return 0;
 		}
 	}
 
-	return possible_name;
+	/* No need to "find best location" for software/app-based RAID, because
+	   MIDI is so small that we always put it in the same place.
+	*/
+
+	return possible_path;
 }
 
 
+/** Create a new within-session audio source */
+boost::shared_ptr<AudioFileSource>
+Session::create_audio_source_for_session (size_t n_chans, string const & base, uint32_t chan, bool destructive)
+{
+	const string path = new_audio_source_path (base, n_chans, chan, destructive, true);
+
+	if (!path.empty()) {
+		return boost::dynamic_pointer_cast<AudioFileSource> (
+			SourceFactory::createWritable (DataType::AUDIO, *this, path, destructive, frame_rate()));
+	} else {
+		throw failed_constructor ();
+	}
+}
+
 /** Create a new within-session MIDI source */
 boost::shared_ptr<MidiSource>
 Session::create_midi_source_for_session (string const & basic_name)
 {
-	std::string name;
-
-	if (name.empty()) {
-		name = new_midi_source_name (basic_name);
+	const string path = new_midi_source_path (basic_name);
+	
+	if (!path.empty()) {
+		return boost::dynamic_pointer_cast<SMFSource> (
+			SourceFactory::createWritable (
+				DataType::MIDI, *this, path, false, frame_rate()));
+	} else {
+		throw failed_constructor ();
 	}
-
-	const string path = new_source_path_from_name (DataType::MIDI, name);
-
-	return boost::dynamic_pointer_cast<SMFSource> (
-		SourceFactory::createWritable (
-			DataType::MIDI, *this, path, false, frame_rate()));
 }
 
 /** Create a new within-session MIDI source */
@@ -3617,7 +3603,13 @@ Session::create_midi_source_by_stealing_name (boost::shared_ptr<Track> track)
 		return boost::shared_ptr<MidiSource>();
 	}
 
-	const string path = new_source_path_from_name (DataType::MIDI, name);
+	/* MIDI files are small, just put them in the first location of the
+	   session source search path.
+	*/
+	vector<string> dirs;
+
+	split (source_search_path(DataType::MIDI), dirs, ':');
+	const string path = Glib::build_filename (dirs.front(), name);
 
 	return boost::dynamic_pointer_cast<SMFSource> (
 		SourceFactory::createWritable (
@@ -4123,18 +4115,13 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
 	boost::shared_ptr<Region> result;
 	boost::shared_ptr<Playlist> playlist;
 	boost::shared_ptr<AudioFileSource> fsource;
-	uint32_t x;
-	char buf[PATH_MAX+1];
 	ChanCount diskstream_channels (track.n_channels());
 	framepos_t position;
 	framecnt_t this_chunk;
 	framepos_t to_do;
 	BufferSet buffers;
-	SessionDirectory sdir(get_best_session_directory_for_new_source ());
-	const string sound_dir = sdir.sound_path();
 	framepos_t len = end - start;
 	bool need_block_size_reset = false;
-	string ext;
 	ChanCount const max_proc = track.max_processor_streams ();
 
 	if (end <= start) {
@@ -4155,29 +4142,22 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
 		goto out;
 	}
 
-	ext = native_header_format_extension (config.get_native_file_header_format(), DataType::AUDIO);
-
 	for (uint32_t chan_n = 0; chan_n < diskstream_channels.n_audio(); ++chan_n) {
 
-		for (x = 0; x < 99999; ++x) {
-			snprintf (buf, sizeof(buf), "%s/%s-%d-bounce-%" PRIu32 "%s", sound_dir.c_str(), playlist->name().c_str(), chan_n, x+1, ext.c_str());
-			if (!Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) {
-				break;
-			}
-		}
-
-		if (x == 99999) {
-			error << string_compose (_("too many bounced versions of playlist \"%1\""), playlist->name()) << endmsg;
+		string base_name = string_compose ("%1-%2-bounce", playlist->name(), chan_n);
+		string path = new_audio_source_path (base_name, diskstream_channels.n_audio(), chan_n, false, true);
+		
+		if (path.empty()) {
 			goto out;
 		}
 
 		try {
 			fsource = boost::dynamic_pointer_cast<AudioFileSource> (
-				SourceFactory::createWritable (DataType::AUDIO, *this, buf, false, frame_rate()));
+				SourceFactory::createWritable (DataType::AUDIO, *this, path, false, frame_rate()));
 		}
 
 		catch (failed_constructor& err) {
-			error << string_compose (_("cannot create new audio file \"%1\" for %2"), buf, track.name()) << endmsg;
+			error << string_compose (_("cannot create new audio file \"%1\" for %2"), path, track.name()) << endmsg;
 			goto out;
 		}
 
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index ffbe55a..db1eb30 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -74,6 +74,7 @@
 #include "pbd/stacktrace.h"
 #include "pbd/convert.h"
 #include "pbd/clear_dir.h"
+#include "pbd/strsplit.h"
 
 #include "ardour/amp.h"
 #include "ardour/audio_diskstream.h"
@@ -1830,47 +1831,15 @@ Session::get_sources_as_xml ()
 	return *node;
 }
 
-string
-Session::path_from_region_name (DataType type, string name, string identifier)
-{
-	char buf[PATH_MAX+1];
-	uint32_t n;
-	SessionDirectory sdir(get_best_session_directory_for_new_source());
-	std::string source_dir = ((type == DataType::AUDIO)
-		? sdir.sound_path() : sdir.midi_path());
-
-        string ext = native_header_format_extension (config.get_native_file_header_format(), type);
-
-	for (n = 0; n < 999999; ++n) {
-		if (identifier.length()) {
-			snprintf (buf, sizeof(buf), "%s%s%" PRIu32 "%s", name.c_str(),
-				  identifier.c_str(), n, ext.c_str());
-		} else {
-			snprintf (buf, sizeof(buf), "%s-%" PRIu32 "%s", name.c_str(),
-					n, ext.c_str());
-		}
-
-		std::string source_path = Glib::build_filename (source_dir, buf);
-
-		if (!Glib::file_test (source_path, Glib::FILE_TEST_EXISTS)) {
-			return source_path;
-		}
-	}
-
-	error << string_compose (_("cannot create new file from region name \"%1\" with ident = \"%2\": too many existing files with similar names"),
-				 name, identifier)
-	      << endmsg;
-
-	return "";
-}
-
-
 int
 Session::load_sources (const XMLNode& node)
 {
 	XMLNodeList nlist;
 	XMLNodeConstIterator niter;
-	boost::shared_ptr<Source> source;
+	boost::shared_ptr<Source> source; /* don't need this but it stops some
+					   * versions of gcc complaining about
+					   * discarded return values.
+					   */
 
 	nlist = node.children();
 
@@ -1887,9 +1856,15 @@ Session::load_sources (const XMLNode& node)
 
                         int user_choice;
 
+			if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
+				error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
+							 PROGRAM_NAME) << endmsg;
+				return -1;
+			}
+
                         if (!no_questions_about_missing_files) {
-                                user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
-                        } else {
+				user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
+			} else {
                                 user_choice = -2;
                         }
 
@@ -1914,8 +1889,41 @@ Session::load_sources (const XMLNode& node)
 
                         case -1:
                         default:
-                                warning << _("A sound file is missing. It will be replaced by silence.") << endmsg;
-                                source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
+				switch (err.type) {
+
+				case DataType::AUDIO:
+					source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
+					break;
+
+				case DataType::MIDI:
+					/* The MIDI file is actually missing so
+					 * just create a new one in the same
+					 * location. Do not announce its
+					 */
+					string fullpath;
+
+					if (!Glib::path_is_absolute (err.path)) {
+						vector<Glib::ustring> sdirs;
+						split (source_search_path (DataType::MIDI), sdirs, ':');
+						if (sdirs.empty()) {
+							fatal << _("Empty MIDI source search path!") << endmsg;
+							/*NOTREACHED*/
+						}
+						fullpath = Glib::build_filename (sdirs.front(), err.path);
+					} else {
+						/* this should be an unrecoverable error: we would be creating a MIDI file outside
+						   the session tree.
+						*/
+						return -1;
+					}
+					/* Note that we do not announce the source just yet - we need to reset its ID before we do that */
+					source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
+					/* reset ID to match the missing one */
+					source->set_id (**niter);
+					/* Now we can announce it */
+					SourceFactory::SourceCreated (source);
+					break;
+				}
                                 break;
                         }
 		}
@@ -2053,7 +2061,7 @@ Session::refresh_disk_space ()
 }
 
 string
-Session::get_best_session_directory_for_new_source ()
+Session::get_best_session_directory_for_new_audio ()
 {
 	vector<space_and_path>::iterator i;
 	string result = _session_dir->root_path();
diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc
index c3bc78c..e32c14a 100644
--- a/libs/ardour/smf_source.cc
+++ b/libs/ardour/smf_source.cc
@@ -71,6 +71,8 @@ SMFSource::SMFSource (Session& s, const string& path, Source::Flag flags)
         assert (!Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
 	existence_check ();
 
+	_flags = Source::Flag (_flags | Empty);
+
 	/* file is not opened until write */
 
 	if (flags & Writable) {
@@ -97,16 +99,15 @@ SMFSource::SMFSource (Session& s, const string& path)
 {
 	/* note that origin remains empty */
 
-	if (init (_path, false)) {
+	if (init (_path, true)) {
 		throw failed_constructor ();
 	}
  
         assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
 	existence_check ();
 
-	/* file is not opened until write */
-
 	if (_flags & Writable) {
+		/* file is not opened until write */
 		return;
 	}
 
@@ -131,12 +132,50 @@ SMFSource::SMFSource (Session& s, const XMLNode& node, bool must_exist)
 		throw failed_constructor ();
 	}
 
-	if (init (_path, true)) {
-		throw failed_constructor ();
+	/* we expect the file to exist, but if no MIDI data was ever added
+	   it will have been removed at last session close. so, we don't
+	   require it to exist if it was marked Empty.
+	*/
+
+	try {
+
+		if (init (_path, true)) {
+			throw failed_constructor ();
+		}
+
+	} catch (MissingSource& err) {
+
+		if (_flags & Source::Empty) {
+			/* we don't care that the file was not found, because
+			   it was empty. But FileSource::init() will have
+			   failed to set our _path correctly, so we have to do
+			   this ourselves. Use the first entry in the search
+			   path for MIDI files, which is assumed to be the
+			   correct "main" location.
+			*/
+			std::vector<Glib::ustring> sdirs;
+			split (s.source_search_path (DataType::MIDI), sdirs, ':');
+			if (sdirs.empty()) {
+				fatal << _("Empty MIDI source search path!") << endmsg;
+				/*NOTREACHED*/
+			}
+			_path = Glib::build_filename (sdirs.front(), _path);
+			/* This might be important, too */
+			_file_is_new = true;
+		} else {
+			/* pass it on */
+			throw;
+		}
 	}
 
-        assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
-	existence_check ();
+	if (!(_flags & Source::Empty)) {
+		assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
+		existence_check ();
+	} else {
+		assert (_flags & Source::Writable);
+		/* file will be opened on write */
+		return;
+	}
 
 	if (open(_path)) {
 		throw failed_constructor ();
@@ -379,6 +418,7 @@ SMFSource::append_event_unlocked_beats (const Evoral::Event<double>& ev)
 
 	Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
 	_last_ev_time_beats = ev.time();
+	_flags = Source::Flag (_flags & ~Empty);
 }
 
 /** Append an event with a timestamp in frames (framepos_t) */
@@ -425,6 +465,7 @@ SMFSource::append_event_unlocked_frames (const Evoral::Event<framepos_t>& ev, fr
 
 	Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
 	_last_ev_time_frames = ev.time();
+	_flags = Source::Flag (_flags & ~Empty);
 }
 
 XMLNode&
@@ -667,10 +708,12 @@ SMFSource::destroy_model ()
 void
 SMFSource::flush_midi ()
 {
-	if (!writable() || (writable() && !_open)) {
+	if (!writable() || _length_beats == 0.0) {
 		return;
 	}
 
+	ensure_disk_file ();
+
 	Evoral::SMF::end_write ();
 	/* data in the file means its no longer removable */
 	mark_nonremovable ();
@@ -687,6 +730,10 @@ SMFSource::set_path (const string& p)
 void
 SMFSource::ensure_disk_file ()
 {
+	if (!writable()) {
+		return;
+	}
+
 	if (_model) {
 		/* We have a model, so write it to disk; see MidiSource::session_saved
 		   for an explanation of what we are doing here.
@@ -702,9 +749,6 @@ SMFSource::ensure_disk_file ()
 		if (!_open) {
 			open_for_write ();
 		}
-
-		/* Flush, which will definitely put something on disk */
-		flush_midi ();
 	}
 }
 
@@ -718,34 +762,3 @@ SMFSource::prevent_deletion ()
 	_flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy));
 }
 
-int
-SMFSource::rename (const string& newname)
-{
-	Glib::Threads::Mutex::Lock lm (_lock);
-	string oldpath = _path;
-	string newpath = _session.new_source_path_from_name (DataType::MIDI, newname);
-
-	if (newpath.empty()) {
-		error << string_compose (_("programming error: %1"), "cannot generate a changed file path") << endmsg;
-		return -1;
-	}
-
-	// Test whether newpath exists, if yes notify the user but continue.
-	if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
-		error << string_compose (_("Programming error! %1 tried to rename a file over another file! It's safe to continue working, but please report this to the developers."), PROGRAM_NAME) << endmsg;
-		return -1;
-	}
-
-	if (Glib::file_test (oldpath.c_str(), Glib::FILE_TEST_EXISTS)) { 
-		/* rename only needed if file exists on disk */
-		if (::rename (oldpath.c_str(), newpath.c_str()) != 0) {
-			error << string_compose (_("cannot rename file %1 to %2 (%3)"), oldpath, newpath, strerror(errno)) << endmsg;
-			return -1;
-		}
-	}
-
-	_name = Glib::path_get_basename (newpath);
-	_path = newpath;
-
-	return 0;
-}
diff --git a/libs/ardour/sndfilesource.cc b/libs/ardour/sndfilesource.cc
index 6b019f6..5465c5e 100644
--- a/libs/ardour/sndfilesource.cc
+++ b/libs/ardour/sndfilesource.cc
@@ -183,6 +183,34 @@ SndFileSource::SndFileSource (Session& s, const string& path, const string& orig
 	}
 }
 
+/** Constructor to be called for recovering files being used for
+ * capture. They are in-session, they already exist, they should not
+ * be writable. They are an odd hybrid (from a constructor point of
+ * view) of the previous two constructors.
+ */
+SndFileSource::SndFileSource (Session& s, const string& path, int chn)
+	: Source (s, DataType::AUDIO, path, Flag (0))
+	  /* the final boolean argument is not used, its value is irrelevant. see audiofilesource.h for explanation */
+	, AudioFileSource (s, path, Flag (0))
+	, _descriptor (0)
+	, _broadcast_info (0)
+	, _capture_start (false)
+	, _capture_end (false)
+	, file_pos (0)
+	, xfade_buf (0)
+{
+	_channel = chn;
+
+	init_sndfile ();
+
+        assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
+	existence_check ();
+
+	if (open()) {
+		throw failed_constructor ();
+	}
+}
+
 void
 SndFileSource::init_sndfile ()
 {
@@ -256,6 +284,14 @@ SndFileSource::open ()
 		delete _broadcast_info;
 		_broadcast_info = 0;
 		_flags = Flag (_flags & ~Broadcast);
+	} 
+
+	/* Set the broadcast flag if the BWF info is already there. We need
+	 * this when recovering or using existing files.
+	 */
+	
+	if (bwf_info_exists) {
+		_flags = Flag (_flags | Broadcast);
 	}
 
 	if (writable()) {
diff --git a/libs/ardour/source_factory.cc b/libs/ardour/source_factory.cc
index 391b205..6d2bb80 100644
--- a/libs/ardour/source_factory.cc
+++ b/libs/ardour/source_factory.cc
@@ -342,6 +342,39 @@ SourceFactory::createWritable (DataType type, Session& s, const std::string& pat
 }
 
 boost::shared_ptr<Source>
+SourceFactory::createForRecovery (DataType type, Session& s, const std::string& path, int chn)
+{
+	/* this might throw failed_constructor(), which is OK */
+
+	if (type == DataType::AUDIO) {
+		Source* src = new SndFileSource (s, path, chn);
+
+#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
+		// boost_debug_shared_ptr_mark_interesting (src, "Source");
+#endif
+		boost::shared_ptr<Source> ret (src);
+
+		if (setup_peakfile (ret, false)) {
+			return boost::shared_ptr<Source>();
+		}
+
+		// no analysis data - this is still basically a new file (we
+		// crashed while recording.
+
+		// always announce these files
+
+		SourceCreated (ret);
+
+		return ret;
+
+	} else if (type == DataType::MIDI) {
+		error << _("Recovery attempted on a MIDI file - not implemented") << endmsg;
+	}
+
+	return boost::shared_ptr<Source> ();
+}
+
+boost::shared_ptr<Source>
 SourceFactory::createFromPlaylist (DataType type, Session& s, boost::shared_ptr<Playlist> p, const PBD::ID& orig, const std::string& name,
 				   uint32_t chn, frameoffset_t start, framecnt_t len, bool copy, bool defer_peaks)
 {
diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc
index 0bb2fea..621d1e2 100644
--- a/libs/ardour/tempo.cc
+++ b/libs/ardour/tempo.cc
@@ -884,6 +884,7 @@ TempoMap::_extend_map (TempoSection* tempo, MeterSection* meter,
 	TempoSection* ts;
 	MeterSection* ms;
 	double beat_frames;
+	double current_frame_exact;
 	framepos_t bar_start_frame;
 
 	DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Extend map to %1 from %2 = %3\n", end, current, current_frame));
@@ -895,11 +896,13 @@ TempoMap::_extend_map (TempoSection* tempo, MeterSection* meter,
 	}
 
 	beat_frames = meter->frames_per_grid (*tempo,_frame_rate);
+	current_frame_exact = current_frame;
 
 	while (current_frame < end) {
 
 		current.beats++;
-		current_frame += beat_frames;
+		current_frame_exact += beat_frames;
+		current_frame = llrint(current_frame_exact);
 
 		if (current.beats > meter->divisions_per_bar()) {
 			current.bars++;
@@ -942,7 +945,8 @@ TempoMap::_extend_map (TempoSection* tempo, MeterSection* meter,
 						                                               tempo->start(), current_frame, tempo->bar_offset()));
 						
 						/* back up to previous beat */
-						current_frame -= beat_frames;
+						current_frame_exact -= beat_frames;
+						current_frame = llrint(current_frame_exact);
 
 						/* set tempo section location
 						 * based on offset from last
@@ -963,7 +967,8 @@ TempoMap::_extend_map (TempoSection* tempo, MeterSection* meter,
 
 						double offset_within_old_beat = (tempo->frame() - current_frame) / beat_frames;
 
-						current_frame += (offset_within_old_beat * beat_frames) + ((1.0 - offset_within_old_beat) * next_beat_frames);
+						current_frame_exact += (offset_within_old_beat * beat_frames) + ((1.0 - offset_within_old_beat) * next_beat_frames);
+						current_frame = llrint(current_frame_exact);
 
 						/* next metric doesn't have to
 						 * match this precisely to
@@ -1012,11 +1017,11 @@ TempoMap::_extend_map (TempoSection* tempo, MeterSection* meter,
 
 		if (current.beats == 1) {
 			DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Bar at %1|1 @ %2\n", current.bars, current_frame));
-			_map.push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current_frame), current.bars, 1));
+			_map.push_back (BBTPoint (*meter, *tempo, current_frame, current.bars, 1));
 			bar_start_frame = current_frame;
 		} else {
 			DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Beat at %1|%2 @ %3\n", current.bars, current.beats, current_frame));
-			_map.push_back (BBTPoint (*meter, *tempo, (framepos_t) llrint(current_frame), current.bars, current.beats));
+			_map.push_back (BBTPoint (*meter, *tempo, current_frame, current.bars, current.beats));
 		}
 
 		if (next_metric == metrics.end()) {
diff --git a/libs/midi++2/midnam_patch.cc b/libs/midi++2/midnam_patch.cc
index 0b8f1ff..7c116f1 100644
--- a/libs/midi++2/midnam_patch.cc
+++ b/libs/midi++2/midnam_patch.cc
@@ -724,14 +724,13 @@ MasterDeviceNames::note_name(const std::string& mode_name,
 		return "";
 	}
 
+	boost::shared_ptr<const NoteNameList> note_names;
 	boost::shared_ptr<const Patch> patch(
 		find_patch(mode_name, channel, PatchPrimaryKey(program, bank)));
-	if (!patch) {
-		return "";
+	if (patch) {
+		note_names = note_name_list(patch->note_list_name());
 	}
 
-	boost::shared_ptr<const NoteNameList> note_names(
-		note_name_list(patch->note_list_name()));
 	if (!note_names) {
 		/* No note names specific to this patch, check the ChannelNameSet */
 		boost::shared_ptr<ChannelNameSet> chan_names = channel_name_set_by_channel(
diff --git a/patchfiles/Korg_Volca_Bass.midnam b/patchfiles/Korg_Volca_Bass.midnam
new file mode 100644
index 0000000..ed07fd8
--- /dev/null
+++ b/patchfiles/Korg_Volca_Bass.midnam
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE MIDINameDocument PUBLIC "-//MIDI Manufacturers Association//DTD MIDINameDocument 1.0//EN" "http://www.midi.org/dtds/MIDINameDocument10.dtd">
+<MIDINameDocument>
+  <Author>David Robillard</Author>
+  <MasterDeviceNames>
+    <Manufacturer>Korg</Manufacturer>
+    <Model>Volca Bass</Model>
+    <CustomDeviceMode Name="Default">
+      <ChannelNameSetAssignments>
+        <ChannelNameSetAssign Channel="1" NameSet="Names"/>
+      </ChannelNameSetAssignments>
+    </CustomDeviceMode>
+    <ChannelNameSet Name="Names">
+      <AvailableForChannels>
+        <AvailableChannel Channel="1" Available="true"/>
+      </AvailableForChannels>
+      <UsesControlNameList Name="Controls"/>
+      <PatchBank Name="User Patches">
+        <PatchNameList Name="User Patches"/>
+      </PatchBank>
+    </ChannelNameSet>
+    <ControlNameList Name="Controls">
+      <Control Type="7bit" Number="5" Name="Slide Time"/>
+      <Control Type="7bit" Number="11" Name="Expression"/>
+      <Control Type="7bit" Number="40" Name="Octave"/>
+      <Control Type="7bit" Number="41" Name="LFO Rate"/>
+      <Control Type="7bit" Number="42" Name="LFO Int"/>
+      <Control Type="7bit" Number="43" Name="VCO Pitch 1"/>
+      <Control Type="7bit" Number="44" Name="VCO Pitch 2"/>
+      <Control Type="7bit" Number="45" Name="VCO Pitch 3"/>
+      <Control Type="7bit" Number="46" Name="EG Attack"/>
+      <Control Type="7bit" Number="47" Name="EG Decay/Release"/>
+      <Control Type="7bit" Number="48" Name="Cutoff EG Int"/>
+      <Control Type="7bit" Number="49" Name="Gate Time"/>
+    </ControlNameList>
+  </MasterDeviceNames>
+</MIDINameDocument>
diff --git a/patchfiles/Korg_Volca_Beats.midnam b/patchfiles/Korg_Volca_Beats.midnam
new file mode 100644
index 0000000..2357936
--- /dev/null
+++ b/patchfiles/Korg_Volca_Beats.midnam
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE MIDINameDocument PUBLIC "-//MIDI Manufacturers Association//DTD MIDINameDocument 1.0//EN" "http://www.midi.org/dtds/MIDINameDocument10.dtd">
+<MIDINameDocument>
+  <Author>David Robillard</Author>
+  <MasterDeviceNames>
+    <Manufacturer>Korg</Manufacturer>
+    <Model>Volca Beats</Model>
+    <CustomDeviceMode Name="Default">
+      <ChannelNameSetAssignments>
+        <ChannelNameSetAssign Channel="10" NameSet="Names"/>
+      </ChannelNameSetAssignments>
+    </CustomDeviceMode>
+    <ChannelNameSet Name="Names">
+      <AvailableForChannels>
+        <AvailableChannel Channel="10" Available="true"/>
+      </AvailableForChannels>
+      <UsesNoteNameList Name="Notes"/>
+      <UsesControlNameList Name="Controls"/>
+      <PatchBank Name="User Patches">
+        <PatchNameList Name="User Patches"/>
+      </PatchBank>
+    </ChannelNameSet>
+    <NoteNameList Name="Notes">
+      <Note Number="37" Name="Kick"/>
+      <Note Number="39" Name="Snare"/>
+      <Note Number="40" Name="Clap"/>
+      <Note Number="43" Name="Closed Hi-hat"/>
+      <Note Number="44" Name="Low Tom"/>
+      <Note Number="47" Name="Open Hi-hat"/>
+      <Note Number="50" Name="Crash Cymbal"/>
+      <Note Number="51" Name="High Tom"/>
+      <Note Number="68" Name="Agogô"/>
+      <Note Number="76" Name="Claves"/>
+    </NoteNameList>
+    <ControlNameList Name="Controls">
+      <Control Type="7bit" Number="40" Name="Kick Level"/>
+      <Control Type="7bit" Number="41" Name="Snare Level"/>
+      <Control Type="7bit" Number="42" Name="Low Tom Level"/>
+      <Control Type="7bit" Number="43" Name="High Tom Level"/>
+      <Control Type="7bit" Number="44" Name="Closed Hat Level"/>
+      <Control Type="7bit" Number="45" Name="Open Hat Level"/>
+      <Control Type="7bit" Number="46" Name="Clap Level"/>
+      <Control Type="7bit" Number="47" Name="Claves Level"/>
+      <Control Type="7bit" Number="48" Name="Agogo Level"/>
+      <Control Type="7bit" Number="49" Name="Crash Level"/>
+      <Control Type="7bit" Number="50" Name="Clap PCM Speed"/>
+      <Control Type="7bit" Number="51" Name="Claves PCM Speed"/>
+      <Control Type="7bit" Number="52" Name="Agogo PCM Speed"/>
+      <Control Type="7bit" Number="53" Name="Crash PCM Speed"/>
+      <Control Type="7bit" Number="54" Name="Stutter Time"/>
+      <Control Type="7bit" Number="55" Name="Stutter Depth"/>
+      <Control Type="7bit" Number="56" Name="Tom Decay"/>
+      <Control Type="7bit" Number="57" Name="Closed Hat Decay"/>
+      <Control Type="7bit" Number="58" Name="Open Hat Decay"/>
+      <Control Type="7bit" Number="59" Name="Hat Grain"/>
+    </ControlNameList>
+  </MasterDeviceNames>
+</MIDINameDocument>
diff --git a/patchfiles/Korg_Volca_Keys.midnam b/patchfiles/Korg_Volca_Keys.midnam
new file mode 100644
index 0000000..2cbe49e
--- /dev/null
+++ b/patchfiles/Korg_Volca_Keys.midnam
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE MIDINameDocument PUBLIC "-//MIDI Manufacturers Association//DTD MIDINameDocument 1.0//EN" "http://www.midi.org/dtds/MIDINameDocument10.dtd">
+<MIDINameDocument>
+  <Author>David Robillard</Author>
+  <MasterDeviceNames>
+    <Manufacturer>Korg</Manufacturer>
+    <Model>Volca Keys</Model>
+    <CustomDeviceMode Name="Default">
+      <ChannelNameSetAssignments>
+        <ChannelNameSetAssign Channel="1" NameSet="Names"/>
+      </ChannelNameSetAssignments>
+    </CustomDeviceMode>
+    <ChannelNameSet Name="Names">
+      <AvailableForChannels>
+        <AvailableChannel Channel="1" Available="true"/>
+      </AvailableForChannels>
+      <UsesControlNameList Name="Controls"/>
+      <PatchBank Name="User Patches">
+        <PatchNameList Name="User Patches"/>
+      </PatchBank>
+    </ChannelNameSet>
+    <ControlNameList Name="Controls">
+      <Control Type="7bit" Number="5" Name="Portamento"/>
+      <Control Type="7bit" Number="11" Name="Expression"/>
+      <Control Type="7bit" Number="40" Name="Voice"/>
+      <Control Type="7bit" Number="41" Name="Octave"/>
+      <Control Type="7bit" Number="42" Name="Detune"/>
+      <Control Type="7bit" Number="43" Name="VCO EG Int"/>
+      <Control Type="7bit" Number="44" Name="Cutoff"/>
+      <Control Type="7bit" Number="45" Name="VCF EG Int"/>
+      <Control Type="7bit" Number="46" Name="LFO Rate"/>
+      <Control Type="7bit" Number="47" Name="LFO Pitch Int"/>
+      <Control Type="7bit" Number="48" Name="LFO Cutoff Int"/>
+      <Control Type="7bit" Number="49" Name="EG Attack"/>
+      <Control Type="7bit" Number="50" Name="EG Decay/Release"/>
+      <Control Type="7bit" Number="51" Name="EG Sustain"/>
+      <Control Type="7bit" Number="52" Name="Delay Time"/>
+      <Control Type="7bit" Number="53" Name="Delay Feedback"/>
+    </ControlNameList>
+  </MasterDeviceNames>
+</MIDINameDocument>

-- 
ardour3 packaging



More information about the pkg-multimedia-commits mailing list