[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