move all destructive functionality into SndFileSource as a mode, and drop Destructive...
authorPaul Davis <paul@linuxaudiosystems.com>
Fri, 3 Nov 2006 02:41:56 +0000 (02:41 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Fri, 3 Nov 2006 02:41:56 +0000 (02:41 +0000)
git-svn-id: svn://localhost/ardour2/trunk@1065 d708f5d6-7413-0410-9779-e7cbd77b26cf

ardour.rc.in
gtk2_ardour/option_editor.cc
libs/ardour/SConscript
libs/ardour/ardour/audiofilesource.h
libs/ardour/ardour/sndfilesource.h
libs/ardour/audiofilesource.cc
libs/ardour/audioregion.cc
libs/ardour/session.cc
libs/ardour/session_state.cc
libs/ardour/sndfilesource.cc
libs/ardour/source_factory.cc

index 735b19c233291e1223b3f8f38d7b96171bc675da..61e7c976b9e9c1904a4a938df8886c769e33e172 100644 (file)
@@ -1,4 +1,4 @@
-<?xml version="1.0"?>
+?xml version="1.0"?>
 <Ardour>
   <MIDI-port tag="%MIDITAG%" device="ardour" type="%MIDITYPE%" mode="duplex"/>
   <MIDI-port tag="control" device="ardour" type="%MIDITYPE%" mode="duplex"/>
@@ -31,6 +31,7 @@
     <Option name="quieten-at-speed" value="1.000000"/>
     <Option name="use-vst" value="yes"/>
     <Option name="use-tranzport" value="yes"/>
+    <Option name="destructive-xfade-msecs" value="500"/>
   </Config>
   <extra>
     <Keyboard edit-button="3" edit-modifier="4" delete-button="3" delete-modifier="1" snap-modifier="32"/>
index 0f1be3dd21f31382c680745884e133f20d4ac933..8f50cfc97565781599724b61f24204e70248aab7 100644 (file)
@@ -318,9 +318,12 @@ OptionEditor::destructo_xfade_adjustment_changed ()
        float val = destructo_xfade_adjustment.get_value();
 
        /* val is in msecs */
+
        
        Config->set_destructive_xfade_msecs ((uint32_t) floor (val));
 
+       cerr << "set destructo fade to " << Config->get_destructive_xfade_msecs () << endl;
+
        if (session) {
                SndFileSource::setup_standard_crossfades (session->frame_rate());
        } 
index 06d53ac0608534fb91b6ee058d962b8e5e7c0eb9..8c6bd36c2d1db85831d32b967524219165724764 100644 (file)
@@ -48,7 +48,6 @@ crossfade.cc
 curve.cc
 cycle_timer.cc
 default_click.cc
-destructive_filesource.cc
 gain.cc
 gdither.cc
 globals.cc
index ac63941a8c27be1a856eddd0ac18d55cb3b9c839..728432db81945ec754847387e55f84624b2f5c51 100644 (file)
@@ -95,6 +95,9 @@ class AudioFileSource : public AudioSource {
        XMLNode& get_state ();
        int set_state (const XMLNode&);
 
+       bool destructive() const { return (_flags & Destructive); }
+       virtual bool set_destructive (bool yn) { return false; }
+
        /* this should really be protected, but C++ is getting stricter
           and creating slots from protected member functions is starting
           to cause issues.
index 6302d8896759ffde63f46d82c5e244c3be1051fe..b810cb538beface5d47d52f60c9f533e049a8c64 100644 (file)
@@ -36,10 +36,7 @@ class SndFileSource : public AudioFileSource {
        /* constructor to be called for new in-session files */
 
        SndFileSource (Session&, std::string path, SampleFormat samp_format, HeaderFormat hdr_format, nframes_t rate, 
-                      Flag flags = AudioFileSource::Flag (AudioFileSource::Writable|
-                                                          AudioFileSource::Removable|
-                                                          AudioFileSource::RemovableIfEmpty|
-                                                          AudioFileSource::CanRename));
+                      Flag flags = SndFileSource::default_writable_flags);
                       
        /* constructor to be called for existing in-session files */
        
@@ -53,6 +50,16 @@ class SndFileSource : public AudioFileSource {
 
        nframes_t natural_position () const;
 
+       nframes_t last_capture_start_frame() const;
+       void mark_capture_start (nframes_t);
+       void mark_capture_end ();
+       void clear_capture_marks();
+
+       bool set_destructive (bool yn);
+
+       static void setup_standard_crossfades (nframes_t sample_rate);
+       static const AudioFileSource::Flag default_writable_flags;
+
   protected:
        void set_header_timeline_position ();
 
@@ -73,6 +80,24 @@ class SndFileSource : public AudioFileSource {
        int open();
        void close();
        int setup_broadcast_info (nframes_t when, struct tm&, time_t);
+
+       /* destructive */
+
+       static nframes_t xfade_frames;
+       static gain_t* out_coefficient;
+       static gain_t* in_coefficient;
+
+       bool          _capture_start;
+       bool          _capture_end;
+       nframes_t      capture_start_frame;
+       nframes_t      file_pos; // unit is frames
+       Sample*        xfade_buf;
+
+       nframes_t crossfade (Sample* data, nframes_t cnt, int dir);
+       void set_timeline_position (nframes_t);
+       nframes_t destructive_write_unlocked (Sample *dst, nframes_t cnt);
+       nframes_t nondestructive_write_unlocked (Sample *dst, nframes_t cnt);
+       void handle_header_position_change ();
 };
 
 } // namespace ARDOUR
index 8fe6c845c070d26921e669e95c15f0a876c0a56d..1fbde870a0a4c65ca50faae76764257f09741961 100644 (file)
@@ -291,6 +291,11 @@ AudioFileSource::set_state (const XMLNode& node)
                _is_embedded = false;
        }
 
+       if ((prop = node.property (X_("destructive"))) != 0) {
+               /* old style, from the period when we had DestructiveFileSource */
+               _flags = Flag (_flags | Destructive);
+       }
+
        return 0;
 }
 
index bbcbcae91ff4c989fcd1c0261d1c5c02ea8b10ab..2f0ae03f2d462aae7c73354f5fcc043bc7eff0c7 100644 (file)
@@ -313,7 +313,9 @@ AudioRegion::~AudioRegion ()
 bool
 AudioRegion::verify_length (nframes_t len)
 {
-       if (boost::dynamic_pointer_cast<DestructiveFileSource>(source())) {
+       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source());
+
+       if (afs && afs->destructive()) {
                return true;
        }
 
@@ -328,7 +330,9 @@ AudioRegion::verify_length (nframes_t len)
 bool
 AudioRegion::verify_start_and_length (nframes_t new_start, nframes_t new_length)
 {
-       if (boost::dynamic_pointer_cast<DestructiveFileSource>(source())) {
+       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source());
+
+       if (afs && afs->destructive()) {
                return true;
        }
 
@@ -342,7 +346,9 @@ AudioRegion::verify_start_and_length (nframes_t new_start, nframes_t new_length)
 bool
 AudioRegion::verify_start (nframes_t pos)
 {
-       if (boost::dynamic_pointer_cast<DestructiveFileSource>(source())) {
+       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source());
+
+       if (afs && afs->destructive()) {
                return true;
        }
 
@@ -357,7 +363,9 @@ AudioRegion::verify_start (nframes_t pos)
 bool
 AudioRegion::verify_start_mutable (nframes_t& new_start)
 {
-       if (boost::dynamic_pointer_cast<DestructiveFileSource>(source())) {
+       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source());
+
+       if (afs && afs->destructive()) {
                return true;
        }
 
@@ -1289,7 +1297,9 @@ AudioRegion::speed_mismatch (float sr) const
 void
 AudioRegion::source_offset_changed ()
 {
-       if (boost::dynamic_pointer_cast<DestructiveFileSource>(sources.front())) {
+       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(sources.front());
+
+       if (afs && afs->destructive()) {
                // set_start (source()->natural_position(), this);
                set_position (source()->natural_position(), this);
        } 
index 99fad0d0130759d63b85f567510b5a4d2e0aec1f..d871f5a859e86ad5b6ff71a40cb45b4247237e55 100644 (file)
@@ -1325,7 +1325,7 @@ Session::set_frame_rate (nframes_t frames_per_second)
        Route::set_automation_interval ((jack_nframes_t) ceil ((double) frames_per_second * 0.25));
 
        // XXX we need some equivalent to this, somehow
-       // DestructiveFileSource::setup_standard_crossfades (frames_per_second);
+       // SndFileSource::setup_standard_crossfades (frames_per_second);
 
        set_dirty();
 
index d9c82f546b12f3302da3e9b915b024773cda59b6..603d3a5c2d41f59cf72ac56c46f4f990fe14f8dd 100644 (file)
@@ -185,7 +185,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
        /* default short fade = 15ms */
 
        Crossfade::set_short_xfade_length ((nframes_t) floor (Config->get_short_xfade_seconds() * frame_rate()));
-       DestructiveFileSource::setup_standard_crossfades (frame_rate());
+       SndFileSource::setup_standard_crossfades (frame_rate());
 
        last_mmc_step.tv_sec = 0;
        last_mmc_step.tv_usec = 0;
@@ -838,13 +838,12 @@ Session::state(bool full_state)
                        boost::shared_ptr<AudioFileSource> fs;
 
                        if ((fs = boost::dynamic_pointer_cast<AudioFileSource> (siter->second)) != 0) {
-                               boost::shared_ptr<DestructiveFileSource> dfs = boost::dynamic_pointer_cast<DestructiveFileSource> (fs);
 
                                /* destructive file sources are OK if they are empty, because
                                   we will re-use them every time.
                                */
 
-                               if (!dfs) {
+                               if (!fs->destructive()) {
                                        if (fs->length() == 0) {
                                                continue;
                                        }
index cb4334c7cbbf13c4aa14d490d957e5221d2bf072..17e45c11d762998a76bdc5b34ceec3726ead8e7e 100644 (file)
 
 #include <ardour/sndfilesource.h>
 
+#include <ardour/utils.h>
+
 #include "i18n.h"
 
 using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
+gain_t* SndFileSource::out_coefficient = 0;
+gain_t* SndFileSource::in_coefficient = 0;
+nframes_t SndFileSource::xfade_frames = 64;
+const AudioFileSource::Flag SndFileSource::default_writable_flags = AudioFileSource::Flag (AudioFileSource::Writable|
+                                                                                          AudioFileSource::Removable|
+                                                                                          AudioFileSource::RemovableIfEmpty|
+                                                                                          AudioFileSource::CanRename);
+
 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
        : AudioFileSource (s, node)
 {
@@ -195,6 +205,17 @@ SndFileSource::init (string idstr)
        */
 
        memset (&_info, 0, sizeof(_info));
+
+       _capture_start = false;
+       _capture_end = false;
+       file_pos = 0;
+
+       if (destructive()) {
+               xfade_buf = new Sample[xfade_frames];
+               timeline_position = header_position_offset;
+       } 
+
+       AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &SndFileSource::handle_header_position_change));
 }
 
 int
@@ -274,6 +295,10 @@ SndFileSource::~SndFileSource ()
        if (_broadcast_info) {
                delete _broadcast_info;
        }
+
+       if (xfade_buf) {
+               delete [] xfade_buf;
+       }
 }
 
 float
@@ -359,6 +384,16 @@ SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const
 
 nframes_t 
 SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
+{
+       if (destructive()) {
+               return destructive_write_unlocked (data, cnt);
+       } else {
+               return nondestructive_write_unlocked (data, cnt);
+       }
+}
+
+nframes_t 
+SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
 {
        if (!writable()) {
                return 0;
@@ -411,6 +446,117 @@ SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
        return cnt;
 }
 
+nframes_t
+SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
+{
+       nframes_t old_file_pos;
+
+       if (!writable()) {
+               return 0;
+       }
+
+       if (_capture_start && _capture_end) {
+
+               /* start and end of capture both occur within the data we are writing,
+                  so do both crossfades.
+               */
+
+               _capture_start = false;
+               _capture_end = false;
+               
+               /* move to the correct location place */
+               file_pos = capture_start_frame - timeline_position;
+               
+               // split cnt in half
+               nframes_t subcnt = cnt / 2;
+               nframes_t ofilepos = file_pos;
+               
+               // fade in
+               if (crossfade (data, subcnt, 1) != subcnt) {
+                       return 0;
+               }
+               
+               file_pos += subcnt;
+               Sample * tmpdata = data + subcnt;
+               
+               // fade out
+               subcnt = cnt - subcnt;
+               if (crossfade (tmpdata, subcnt, 0) != subcnt) {
+                       return 0;
+               }
+               
+               file_pos = ofilepos; // adjusted below
+
+       } else if (_capture_start) {
+
+               /* start of capture both occur within the data we are writing,
+                  so do the fade in
+               */
+
+               _capture_start = false;
+               _capture_end = false;
+               
+               /* move to the correct location place */
+               file_pos = capture_start_frame - timeline_position;
+
+               if (crossfade (data, cnt, 1) != cnt) {
+                       return 0;
+               }
+               
+       } else if (_capture_end) {
+
+               /* end of capture both occur within the data we are writing,
+                  so do the fade out
+               */
+
+               _capture_start = false;
+               _capture_end = false;
+               
+               if (crossfade (data, cnt, 0) != cnt) {
+                       return 0;
+               }
+
+       } else {
+
+               /* in the middle of recording */
+
+               if (write_float (data, file_pos, cnt) != cnt) {
+                       return 0;
+               }
+       }
+
+       old_file_pos = file_pos;
+       update_length (file_pos, cnt);
+       file_pos += cnt;
+
+       if (_build_peakfiles) {
+               PeakBuildRecord *pbr = 0;
+               
+               if (pending_peak_builds.size()) {
+                       pbr = pending_peak_builds.back();
+               }
+               
+               if (pbr && pbr->frame + pbr->cnt == old_file_pos) {
+                       
+                       /* the last PBR extended to the start of the current write,
+                          so just extend it again.
+                       */
+                       
+                       pbr->cnt += cnt;
+               } else {
+                       pending_peak_builds.push_back (new PeakBuildRecord (old_file_pos, cnt));
+               }
+               
+               _peaks_built = false;
+       }
+
+       if (_build_peakfiles) {
+               queue_for_peaks (shared_from_this ());
+       }
+       
+       return cnt;
+}
+
 int
 SndFileSource::update_header (nframes_t when, struct tm& now, time_t tnow)
 {      
@@ -526,3 +672,221 @@ SndFileSource::natural_position() const
 {
        return timeline_position;
 }
+
+bool
+SndFileSource::set_destructive (bool yn)
+{
+       if (yn) {
+               _flags = Flag (_flags | Destructive);
+               clear_capture_marks ();
+               timeline_position = header_position_offset;
+       } else {
+               _flags = Flag (_flags & ~Destructive);
+               timeline_position = 0;
+       }
+
+       return true;
+}
+
+void
+SndFileSource::clear_capture_marks ()
+{
+       _capture_start = false;
+       _capture_end = false;
+}      
+
+void
+SndFileSource::mark_capture_start (nframes_t pos)
+{
+       if (destructive()) {
+               if (pos < timeline_position) {
+                       _capture_start = false;
+               } else {
+                       _capture_start = true;
+                       capture_start_frame = pos;
+               }
+       }
+}
+
+void
+SndFileSource::mark_capture_end()
+{
+       if (destructive()) {
+               _capture_end = true;
+       }
+}
+
+nframes_t
+SndFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
+{
+       nframes_t xfade = min (xfade_frames, cnt);
+       nframes_t nofade = cnt - xfade;
+       Sample* fade_data = 0;
+       nframes_t fade_position = 0; // in frames
+       ssize_t retval;
+       nframes_t file_cnt;
+
+       if (fade_in) {
+               fade_position = file_pos;
+               fade_data = data;
+       } else {
+               fade_position = file_pos + nofade;
+               fade_data = data + nofade;
+       }
+
+       if (fade_position > _length) {
+               
+               /* read starts beyond end of data, just memset to zero */
+               
+               file_cnt = 0;
+
+       } else if (fade_position + xfade > _length) {
+               
+               /* read ends beyond end of data, read some, memset the rest */
+               
+               file_cnt = _length - fade_position;
+
+       } else {
+               
+               /* read is entirely within data */
+
+               file_cnt = xfade;
+       }
+
+       if (file_cnt) {
+               
+               if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
+                       if (retval >= 0 && errno == EAGAIN) {
+                               /* XXX - can we really trust that errno is meaningful here?  yes POSIX, i'm talking to you.
+                                * short or no data there */
+                               memset (xfade_buf, 0, xfade * sizeof(Sample));
+                       } else {
+                               error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
+                               return 0;
+                       }
+               }
+       } 
+
+       if (file_cnt != xfade) {
+               nframes_t delta = xfade - file_cnt;
+               memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
+       }
+       
+       if (nofade && !fade_in) {
+               if (write_float (data, file_pos, nofade) != nofade) {
+                       error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
+                       return 0;
+               }
+       }
+
+       if (xfade == xfade_frames) {
+
+               nframes_t n;
+
+               /* use the standard xfade curve */
+               
+               if (fade_in) {
+
+                       /* fade new material in */
+                       
+                       for (n = 0; n < xfade; ++n) {
+                               xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
+                       }
+
+               } else {
+
+
+                       /* fade new material out */
+                       
+                       for (n = 0; n < xfade; ++n) {
+                               xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
+                       }
+               }
+
+       } else if (xfade) {
+
+               gain_t in[xfade];
+               gain_t out[xfade];
+
+               /* short xfade, compute custom curve */
+
+               compute_equal_power_fades (xfade, in, out);
+
+               for (nframes_t n = 0; n < xfade; ++n) {
+                       xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);                
+               }
+       }
+
+       if (xfade) {
+               if (write_float (xfade_buf, fade_position, xfade) != xfade) {
+                       error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
+                       return 0;
+               }
+       }
+       
+       if (fade_in && nofade) {
+               if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
+                       error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
+                       return 0;
+               }
+       }
+
+       return cnt;
+}
+
+nframes_t
+SndFileSource::last_capture_start_frame () const
+{
+       return capture_start_frame;
+}
+
+void
+SndFileSource::handle_header_position_change ()
+{
+       if (destructive()) {
+               if ( _length != 0 ) {
+                       error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
+                       //in the future, pop up a dialog here that allows user to regenerate file with new start offset
+               } else if (writable()) {
+                       timeline_position = header_position_offset;
+                       set_header_timeline_position ();  //this will get flushed if/when the file is recorded to
+               }
+       }
+}
+
+void
+SndFileSource::setup_standard_crossfades (nframes_t rate)
+{
+       /* This static method is assumed to have been called by the Session
+          before any DFS's are created.
+       */
+
+       xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
+
+       cerr << "based on " << Config->get_destructive_xfade_msecs() << " msecs, xfade_frames = " << xfade_frames << endl;
+
+       if (out_coefficient) {
+               delete [] out_coefficient;
+       }
+
+       if (in_coefficient) {
+               delete [] in_coefficient;
+       }
+
+       out_coefficient = new gain_t[xfade_frames];
+       in_coefficient = new gain_t[xfade_frames];
+
+       compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
+}
+
+void
+SndFileSource::set_timeline_position (nframes_t pos)
+{
+       // destructive track timeline postion does not change
+       // except at instantion or when header_position_offset 
+       // (session start) changes
+
+       if (!destructive()) {
+               AudioFileSource::set_timeline_position (pos);
+       } 
+}
index 7e639590c5737bfa7305920544a37d6e288dad75..9a3902147b83b08321848dda94b4badc69a88e58 100644 (file)
@@ -55,37 +55,25 @@ SourceFactory::setup_peakfile (boost::shared_ptr<Source> s)
 boost::shared_ptr<Source>
 SourceFactory::create (Session& s, const XMLNode& node)
 {
-       if (node.property (X_("destructive")) != 0) {
-
-               boost::shared_ptr<Source> ret (new DestructiveFileSource (s, node));
+       try {
+               boost::shared_ptr<Source> ret (new CoreAudioSource (s, node));
                if (setup_peakfile (ret)) {
                        return boost::shared_ptr<Source>();
                }
                SourceCreated (ret);
                return ret;
-               
-       } else {
-               
-               try {
-                       boost::shared_ptr<Source> ret (new CoreAudioSource (s, node));
-                       if (setup_peakfile (ret)) {
-                               return boost::shared_ptr<Source>();
-                       }
-                       SourceCreated (ret);
-                       return ret;
-               } 
-               
-               
-               catch (failed_constructor& err) {
-                       boost::shared_ptr<Source> ret (new SndFileSource (s, node));
-                       if (setup_peakfile (ret)) {
-                               return boost::shared_ptr<Source>();
-                       }
-                       SourceCreated (ret);
-                       return ret;
+       } 
+       
+       
+       catch (failed_constructor& err) {
+               boost::shared_ptr<Source> ret (new SndFileSource (s, node));
+               if (setup_peakfile (ret)) {
+                       return boost::shared_ptr<Source>();
                }
+               SourceCreated (ret);
+               return ret;
        }
-       
+
        return boost::shared_ptr<Source>();
 }
 
@@ -94,24 +82,12 @@ SourceFactory::create (Session& s, const XMLNode& node)
 boost::shared_ptr<Source>
 SourceFactory::create (Session& s, const XMLNode& node)
 {
-       if (node.property (X_("destructive")) != 0) {
-               
-               boost::shared_ptr<Source> ret (new DestructiveFileSource (s, node));
-               if (setup_peakfile (ret)) {
-                       return boost::shared_ptr<Source>();
-               }
-               SourceCreated (ret);
-               return ret;
-               
-       } else {
-               
-               boost::shared_ptr<Source> ret (new SndFileSource (s, node));
-               if (setup_peakfile (ret)) {
-                       return boost::shared_ptr<Source>();
-               }
-               SourceCreated (ret);
-               return ret;
+       boost::shared_ptr<Source> ret (new SndFileSource (s, node));
+       if (setup_peakfile (ret)) {
+               return boost::shared_ptr<Source>();
        }
+       SourceCreated (ret);
+       return ret;
 }
 
 #endif // HAVE_COREAUDIO
@@ -120,37 +96,42 @@ SourceFactory::create (Session& s, const XMLNode& node)
 boost::shared_ptr<Source>
 SourceFactory::createReadable (Session& s, string idstr, AudioFileSource::Flag flags, bool announce)
 {
-       if (flags & Destructive) {
-               boost::shared_ptr<Source> ret (new DestructiveFileSource (s, idstr, flags));
-               if (setup_peakfile (ret)) {
-                       return boost::shared_ptr<Source>();
-               }
-               if (announce) {
-                       SourceCreated (ret);
-               }
-               return ret;
-       }
+       if (!(flags & Destructive)) {
 
-       try {
-               boost::shared_ptr<Source> ret (new CoreAudioSource (s, idstr, flags));
-               if (setup_peakfile (ret)) {
-                       return boost::shared_ptr<Source>();
+               try {
+                       boost::shared_ptr<Source> ret (new CoreAudioSource (s, idstr, flags));
+                       if (setup_peakfile (ret)) {
+                               return boost::shared_ptr<Source>();
+                       }
+                       if (announce) {
+                               SourceCreated (ret);
+                       }
+                       return ret;
                }
-               if (announce) {
-                       SourceCreated (ret);
+               
+               catch (failed_constructor& err) {
+                       boost::shared_ptr<Source> ret (new SndFileSource (s, idstr, flags));
+                       if (setup_peakfile (ret)) {
+                               return boost::shared_ptr<Source>();
+                       }
+                       if (announce) {
+                               SourceCreated (ret);
+                       }
+                       return ret;
                }
-               return ret;
-       }
 
-       catch (failed_constructor& err) {
-               boost::shared_ptr<Source> ret (new SndFileSource (s, idstr, flags));
-               if (setup_peakfile (ret)) {
-                       return boost::shared_ptr<Source>();
-               }
-               if (announce) {
-                       SourceCreated (ret);
+       } else {
+
+               catch (failed_constructor& err) {
+                       boost::shared_ptr<Source> ret (new SndFileSource (s, idstr, flags));
+                       if (setup_peakfile (ret)) {
+                               return boost::shared_ptr<Source>();
+                       }
+                       if (announce) {
+                               SourceCreated (ret);
+                       }
+                       return ret;
                }
-               return ret;
        }
 
        return boost::shared_ptr<Source>();
@@ -178,30 +159,20 @@ SourceFactory::createWritable (Session& s, std::string path, bool destructive, n
 {
        /* this might throw failed_constructor(), which is OK */
        
-       if (destructive) {
-               boost::shared_ptr<Source> ret (new DestructiveFileSource (s, path,
-                                                                         Config->get_native_file_data_format(),
-                                                                         Config->get_native_file_header_format(),
-                                                                         rate));
-               if (setup_peakfile (ret)) {
-                       return boost::shared_ptr<Source>();
-               }
-               if (announce) {
-                       SourceCreated (ret);
-               }
-               return ret;
-               
-       } else {
-               boost::shared_ptr<Source> ret (new SndFileSource (s, path, 
-                                                                 Config->get_native_file_data_format(),
-                                                                 Config->get_native_file_header_format(),
-                                                                 rate));
-               if (setup_peakfile (ret)) {
-                       return boost::shared_ptr<Source>();
-               }
-               if (announce) {
-                       SourceCreated (ret);
-               }
-               return ret;
+       boost::shared_ptr<Source> ret (new SndFileSource 
+                                      (s, path, 
+                                       Config->get_native_file_data_format(),
+                                       Config->get_native_file_header_format(),
+                                       rate,
+                                       (destructive ? SndFileSource::default_writable_flags : 
+                                        AudioFileSource::Flag 
+                                        (SndFileSource::default_writable_flags | AudioFileSource::Destructive))));
+
+       if (setup_peakfile (ret)) {
+               return boost::shared_ptr<Source>();
+       }
+       if (announce) {
+               SourceCreated (ret);
        }
+       return ret;
 }