diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2008-03-17 20:54:03 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2008-03-17 20:54:03 +0000 |
commit | 997e4b1f9cd7ccfc704b7c035051da7f60d831e7 (patch) | |
tree | 1236e40183b677abf4a2882e4cfe8e0a345eb24d /libs/ardour | |
parent | 19a4b990325577fc949ccd5d5fbad4520eb1df56 (diff) |
merge with 2.0-ongoing @ rev 3147
git-svn-id: svn://localhost/ardour2/branches/3.0@3152 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour')
35 files changed, 828 insertions, 450 deletions
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index 4c13c82cf7..b50aecbcb3 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -134,6 +134,7 @@ smf_reader.cc smf_source.cc sndfile_helpers.cc sndfilesource.cc +sndfileimportable.cc source.cc source_factory.cc tape_file_matcher.cc @@ -152,7 +153,7 @@ osc_files = [ 'osc.cc' ] vst_files = [ 'vst_plugin.cc', 'session_vst.cc' ] lv2_files = [ 'lv2_plugin.cc' ] audiounit_files = [ 'audio_unit.cc' ] -coreaudio_files = [ 'coreaudiosource.cc' ] +coreaudio_files = [ 'coreaudiosource.cc', 'caimportable.cc' ] extra_sources = [ ] timefx_sources = [ ] diff --git a/libs/ardour/ardour/audiofilesource.h b/libs/ardour/ardour/audiofilesource.h index 0e8b6e4fde..de388a06fc 100644 --- a/libs/ardour/ardour/audiofilesource.h +++ b/libs/ardour/ardour/audiofilesource.h @@ -170,6 +170,8 @@ class AudioFileSource : public AudioSource { bool removable() const; bool writable() const { return _flags & Writable; } + static Sample* get_interleave_buffer (nframes_t size); + private: Glib::ustring old_peak_path (Glib::ustring audio_path); Glib::ustring broken_peak_path (Glib::ustring audio_path); diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h index e88e10d521..81b7ef7c57 100644 --- a/libs/ardour/ardour/audioregion.h +++ b/libs/ardour/ardour/audioregion.h @@ -155,7 +155,8 @@ class AudioRegion : public Region void recompute_gain_at_end (); void recompute_gain_at_start (); - nframes_t _read_at (const SourceList&, Sample *buf, Sample *mixdown_buffer, + nframes_t _read_at (const SourceList&, nframes_t limit, + Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t position, nframes_t cnt, uint32_t chan_n = 0, nframes_t read_frames = 0, diff --git a/libs/ardour/ardour/caimportable.h b/libs/ardour/ardour/caimportable.h new file mode 100644 index 0000000000..dc7f5769ae --- /dev/null +++ b/libs/ardour/ardour/caimportable.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2007 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __ardour_ca_importable_source_h__ +#define __ardour_ca_importable_source_h__ + +#include <pbd/failed_constructor.h> +#include <ardour/types.h> +#include <ardour/importable_source.h> + +#include <appleutility/CAAudioFile.h> + +namespace ARDOUR { + +class CAImportableSource : public ImportableSource { + public: + CAImportableSource (const std::string& path); + virtual ~CAImportableSource(); + + nframes_t read (Sample* buffer, nframes_t nframes); + uint32_t channels() const; + nframes_t length() const; + nframes_t samplerate() const; + void seek (nframes_t pos); + + protected: + mutable CAAudioFile af; +}; + +} + +#endif /* __ardour_ca_importable_source_h__ */ diff --git a/libs/ardour/ardour/configuration_vars.h b/libs/ardour/ardour/configuration_vars.h index f21de9be37..732585982d 100644 --- a/libs/ardour/ardour/configuration_vars.h +++ b/libs/ardour/ardour/configuration_vars.h @@ -33,8 +33,8 @@ CONFIG_VARIABLE (std::string, midi_port_name, "midi-port-name", "default") CONFIG_VARIABLE (bool, trace_midi_input, "trace-midi-input", false) CONFIG_VARIABLE (bool, trace_midi_output, "trace-midi-output", false) CONFIG_VARIABLE (bool, send_mtc, "send-mtc", false) -CONFIG_VARIABLE (bool, send_mmc, "send-mmc", false) -CONFIG_VARIABLE (bool, mmc_control, "mmc-control", false) +CONFIG_VARIABLE (bool, send_mmc, "send-mmc", true) +CONFIG_VARIABLE (bool, mmc_control, "mmc-control", true) CONFIG_VARIABLE (bool, midi_feedback, "midi-feedback", false) CONFIG_VARIABLE (uint8_t, mmc_receive_device_id, "mmc-receive-device-id", 0) CONFIG_VARIABLE (uint8_t, mmc_send_device_id, "mmc-send-device-id", 0) @@ -157,6 +157,7 @@ CONFIG_VARIABLE (std::string, keyboard_layout, "keyboard-layout", "ansi") CONFIG_VARIABLE (std::string, default_bindings, "default-bindings", "ardour") CONFIG_VARIABLE (bool, default_narrow_ms, "default-narrow_ms", false) CONFIG_VARIABLE (bool, rubberbanding_snaps_to_grid, "rubberbanding-snaps-to-grid", false) +CONFIG_VARIABLE (long, font_scale, "font-scale", 102400) /* denormal management */ diff --git a/libs/ardour/ardour/coreaudiosource.h b/libs/ardour/ardour/coreaudiosource.h index ad21188531..d7282b35bd 100644 --- a/libs/ardour/ardour/coreaudiosource.h +++ b/libs/ardour/ardour/coreaudiosource.h @@ -21,7 +21,6 @@ #define __coreaudio_source_h__ #include <appleutility/CAAudioFile.h> - #include <ardour/audiofilesource.h> namespace ARDOUR { @@ -48,11 +47,8 @@ class CoreAudioSource : public AudioFileSource { mutable CAAudioFile af; uint16_t n_channels; - mutable float *tmpbuf; - mutable nframes_t tmpbufsize; - mutable Glib::Mutex _tmpbuf_lock; - void init (); + int safe_read (Sample*, nframes_t start, nframes_t cnt, AudioBufferList&) const; }; }; /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/importable_source.h b/libs/ardour/ardour/importable_source.h index 5845d841b6..a33cf567e7 100644 --- a/libs/ardour/ardour/importable_source.h +++ b/libs/ardour/ardour/importable_source.h @@ -20,7 +20,6 @@ #ifndef __ardour_importable_source_h__ #define __ardour_importable_source_h__ -#include <sndfile.h> #include <pbd/failed_constructor.h> #include <ardour/types.h> @@ -28,32 +27,15 @@ namespace ARDOUR { class ImportableSource { public: - ImportableSource (const std::string& path) - : in (sf_open (path.c_str(), SFM_READ, &sf_info), sf_close) - { - if (!in) throw failed_constructor(); - - } - + ImportableSource () {} virtual ~ImportableSource() {} - virtual nframes_t read (Sample* buffer, nframes_t nframes) { - nframes_t per_channel = nframes / sf_info.channels; - per_channel = sf_readf_float (in.get(), buffer, per_channel); - return per_channel * sf_info.channels; - } - + virtual nframes_t read (Sample* buffer, nframes_t nframes) = 0; virtual float ratio() const { return 1.0f; } - - uint channels() const { return sf_info.channels; } - - nframes_t length() const { return sf_info.frames; } - - nframes_t samplerate() const { return sf_info.samplerate; } - -protected: - SF_INFO sf_info; - boost::shared_ptr<SNDFILE> in; + virtual uint32_t channels() const = 0; + virtual nframes_t length() const = 0; + virtual nframes_t samplerate() const = 0; + virtual void seek (nframes_t pos) = 0; }; } diff --git a/libs/ardour/ardour/resampled_source.h b/libs/ardour/ardour/resampled_source.h index 8ca56b52d3..6eca4cda98 100644 --- a/libs/ardour/ardour/resampled_source.h +++ b/libs/ardour/ardour/resampled_source.h @@ -30,18 +30,21 @@ namespace ARDOUR { class ResampledImportableSource : public ImportableSource { public: - ResampledImportableSource (const std::string& path, - nframes_t rate, SrcQuality); + ResampledImportableSource (boost::shared_ptr<ImportableSource>, nframes_t rate, SrcQuality); ~ResampledImportableSource (); nframes_t read (Sample* buffer, nframes_t nframes); - float ratio() const { return src_data.src_ratio; } + uint32_t channels() const { return source->channels(); } + nframes_t length() const { return source->length(); } + nframes_t samplerate() const { return source->samplerate(); } + void seek (nframes_t pos) { source->seek (pos); } static const uint32_t blocksize; private: + boost::shared_ptr<ImportableSource> source; float* input; SRC_STATE* src_state; SRC_DATA src_data; diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index bc77157e9f..67a641ff59 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -175,6 +175,7 @@ class Session : public PBD::StatefulDestructible union { void* ptr; bool yes_or_no; + nframes_t target2_frame; SlaveSource slave; Route* route; }; diff --git a/libs/ardour/ardour/sndfileimportable.h b/libs/ardour/ardour/sndfileimportable.h new file mode 100644 index 0000000000..5cd84f4f5f --- /dev/null +++ b/libs/ardour/ardour/sndfileimportable.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2007 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __ardour_sndfile_importable_source_h__ +#define __ardour_sndfile_importable_source_h__ + +#include <boost/shared_ptr.hpp> +#include <sndfile.h> +#include <pbd/failed_constructor.h> +#include <ardour/types.h> +#include <ardour/importable_source.h> + +namespace ARDOUR { + +class SndFileImportableSource : public ImportableSource { + public: + SndFileImportableSource (const std::string& path); + virtual ~SndFileImportableSource(); + + nframes_t read (Sample* buffer, nframes_t nframes); + uint32_t channels() const; + nframes_t length() const; + nframes_t samplerate() const; + void seek (nframes_t pos); + + protected: + SF_INFO sf_info; + boost::shared_ptr<SNDFILE> in; + +}; + +} + +#endif /* __ardour_sndfile_importable_source_h__ */ diff --git a/libs/ardour/ardour/sndfilesource.h b/libs/ardour/ardour/sndfilesource.h index 4fd71a4c96..dc83fc6ec1 100644 --- a/libs/ardour/ardour/sndfilesource.h +++ b/libs/ardour/ardour/sndfilesource.h @@ -102,7 +102,6 @@ class SndFileSource : public AudioFileSource { void handle_header_position_change (); static int64_t get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& exists); - static Sample* get_interleave_buffer (nframes_t size); }; } // namespace ARDOUR diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index 5c32b34e10..e1853e557c 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -2220,7 +2220,7 @@ AudioDiskstream::add_channel (uint32_t how_many) int AudioDiskstream::remove_channel_from (boost::shared_ptr<ChannelList> c, uint32_t how_many) { - while (--how_many && !c->empty()) { + while (how_many-- && !c->empty()) { delete c->back(); c->pop_back(); } diff --git a/libs/ardour/audio_unit.cc b/libs/ardour/audio_unit.cc index 9132957743..e517964024 100644 --- a/libs/ardour/audio_unit.cc +++ b/libs/ardour/audio_unit.cc @@ -93,6 +93,13 @@ AUPlugin::AUPlugin (AudioEngine& engine, Session& session, boost::shared_ptr<CAC streamFormat.mSampleRate = session.frame_rate(); streamFormat.mFormatID = kAudioFormatLinearPCM; streamFormat.mFormatFlags = kAudioFormatFlagIsFloat|kAudioFormatFlagIsPacked|kAudioFormatFlagIsNonInterleaved; + +#ifdef __LITTLE_ENDIAN__ + /* relax */ +#else + streamFormat.mFormatFlags |= kAudioFormatFlagIsBigEndian; +#endif + streamFormat.mBitsPerChannel = 32; streamFormat.mFramesPerPacket = 1; @@ -130,8 +137,6 @@ AUPlugin::discover_parameters () { /* discover writable parameters */ - cerr << "get param info, there are " << global_elements << " global elements\n"; - AudioUnitScope scopes[] = { kAudioUnitScope_Global, kAudioUnitScope_Output, @@ -144,8 +149,6 @@ AUPlugin::discover_parameters () AUParamInfo param_info (unit->AU(), false, false, scopes[i]); - cerr << "discovered " << param_info.NumParams() << " parameters in scope " << i << endl; - for (uint32_t i = 0; i < param_info.NumParams(); ++i) { AUParameterDescriptor d; @@ -328,7 +331,7 @@ AUPlugin::activate () if (!initialized) { OSErr err; if ((err = unit->Initialize()) != noErr) { - error << string_compose (_("AUPlugin: cannot initialize plugin (err = %1)"), err) << endmsg; + error << string_compose (_("AUPlugin: %1 cannot initialize plugin (err = %2)"), name(), err) << endmsg; } else { frames_processed = 0; initialized = true; @@ -453,9 +456,10 @@ uint32_t AUPlugin::output_streams() const { if (!(format_set & 0x2)) { - warning << _("AUPlugin: output_streams() called without any format set!") << endmsg; + warning << string_compose (_("AUPlugin: %1 output_streams() called without any format set!"), name()) << endmsg; return 1; } + return streamFormat.mChannelsPerFrame; } @@ -819,7 +823,6 @@ AUPluginInfo::discover_by_description (PluginInfoList& plugs, CAComponentDescrip info->n_inputs = -1; info->n_outputs = -1; - plugs.push_back (info); comp = FindNextComponent (comp, &desc); diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 8d2589db0e..bdc1e8f0e4 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -82,9 +82,6 @@ AudioEngine::AudioEngine (string client_name) if (connect_to_jack (client_name)) { throw NoBackendAvailable (); } - - start_metering_thread(); - Port::set_engine (this); } @@ -169,6 +166,8 @@ AudioEngine::start () } else { // error << _("cannot activate JACK client") << endmsg; } + + start_metering_thread(); } return _running ? 0 : -1; @@ -179,11 +178,11 @@ AudioEngine::stop (bool forever) { if (_running) { _running = false; + stop_metering_thread (); if (forever) { jack_client_t* foo = _jack; _jack = 0; jack_client_close (foo); - stop_metering_thread (); } else { jack_deactivate (_jack); } @@ -455,8 +454,9 @@ void AudioEngine::start_metering_thread () { if (m_meter_thread == 0) { + g_atomic_int_set (&m_meter_exit, 0); m_meter_thread = Glib::Thread::create (sigc::mem_fun(this, &AudioEngine::meter_thread), - 500000, true, true, Glib::THREAD_PRIORITY_NORMAL); + 500000, true, true, Glib::THREAD_PRIORITY_NORMAL); } } @@ -861,6 +861,8 @@ AudioEngine::halted (void *arg) AudioEngine* ae = static_cast<AudioEngine *> (arg); bool was_running = ae->_running; + ae->stop_metering_thread (); + ae->_running = false; ae->_buffer_size = 0; ae->_frame_rate = 0; @@ -1178,6 +1180,7 @@ AudioEngine::disconnect_from_jack () _frame_rate = 0; if (_running) { + stop_metering_thread (); _running = false; Stopped(); /* EMIT SIGNAL */ } @@ -1255,6 +1258,8 @@ AudioEngine::reconnect_to_jack () Running (); /* EMIT SIGNAL*/ + start_metering_thread (); + return 0; } diff --git a/libs/ardour/audiofilesource.cc b/libs/ardour/audiofilesource.cc index 00e0f925df..268c4e18bb 100644 --- a/libs/ardour/audiofilesource.cc +++ b/libs/ardour/audiofilesource.cc @@ -38,6 +38,7 @@ #include <glibmm/miscutils.h> #include <glibmm/fileutils.h> +#include <glibmm/thread.h> #include <ardour/audiofilesource.h> #include <ardour/sndfile_helpers.h> @@ -70,6 +71,21 @@ uint64_t AudioFileSource::header_position_offset = 0; /* XXX maybe this too */ char AudioFileSource::bwf_serial_number[13] = "000000000000"; +struct SizedSampleBuffer { + nframes_t size; + Sample* buf; + + SizedSampleBuffer (nframes_t sz) : size (sz) { + buf = new Sample[size]; + } + + ~SizedSampleBuffer() { + delete [] buf; + } +}; + +Glib::StaticPrivate<SizedSampleBuffer> thread_interleave_buffer = GLIBMM_STATIC_PRIVATE_INIT; + AudioFileSource::AudioFileSource (Session& s, ustring path, Flag flags) : AudioSource (s, path), _flags (flags), _channel (0) @@ -678,6 +694,7 @@ AudioFileSource::safe_file_extension(ustring file) { return !(file.rfind(".wav") == ustring::npos && file.rfind(".aiff")== ustring::npos && + file.rfind(".caf")== ustring::npos && file.rfind(".aif") == ustring::npos && file.rfind(".amb") == ustring::npos && file.rfind(".snd") == ustring::npos && @@ -711,3 +728,22 @@ AudioFileSource::mark_immutable () _flags = Flag (_flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy|CanRename)); } } + + +Sample* +AudioFileSource::get_interleave_buffer (nframes_t size) +{ + SizedSampleBuffer* ssb; + + if ((ssb = thread_interleave_buffer.get()) == 0) { + ssb = new SizedSampleBuffer (size); + thread_interleave_buffer.set (ssb); + } + + if (ssb->size < size) { + ssb = new SizedSampleBuffer (size); + thread_interleave_buffer.set (ssb); + } + + return ssb->buf; +} diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc index 5e0cd136ff..7c0893f288 100644 --- a/libs/ardour/audioregion.cc +++ b/libs/ardour/audioregion.cc @@ -291,7 +291,7 @@ nframes64_t AudioRegion::read (Sample* buf, nframes64_t position, nframes64_t cnt, int channel) const { /* raw read, no fades, no gain, nada */ - return _read_at (_sources, buf, 0, 0, _position + position, cnt, channel, 0, 0, true); + return _read_at (_sources, _length, buf, 0, 0, _position + position, cnt, channel, 0, 0, true); } nframes_t @@ -300,18 +300,19 @@ AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, n uint32_t chan_n, nframes_t read_frames, nframes_t skip_frames) const { /* regular diskstream/butler read complete with fades etc */ - return _read_at (_sources, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, read_frames, skip_frames, false); + return _read_at (_sources, _length, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, read_frames, skip_frames, false); } nframes_t AudioRegion::master_read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t position, nframes_t cnt, uint32_t chan_n) const { - return _read_at (_master_sources, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, 0, 0); + return _read_at (_master_sources, _master_sources.front()->length(), buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, 0, 0); } nframes_t -AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buffer, float *gain_buffer, +AudioRegion::_read_at (const SourceList& srcs, nframes_t limit, + Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t position, nframes_t cnt, uint32_t chan_n, nframes_t read_frames, @@ -337,11 +338,11 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff buf_offset = 0; } - if (internal_offset >= _length) { + if (internal_offset >= limit) { return 0; /* read nothing */ } - if ((to_read = min (cnt, _length - internal_offset)) == 0) { + if ((to_read = min (cnt, limit - internal_offset)) == 0) { return 0; /* read nothing */ } @@ -394,13 +395,13 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff if (internal_offset < fade_in_length) { - nframes_t limit; + nframes_t fi_limit; - limit = min (to_read, fade_in_length - internal_offset); + fi_limit = min (to_read, fade_in_length - internal_offset); - _fade_in->curve().get_vector (internal_offset, internal_offset+limit, gain_buffer, limit); + _fade_in->curve().get_vector (internal_offset, internal_offset+fi_limit, gain_buffer, fi_limit); - for (nframes_t n = 0; n < limit; ++n) { + for (nframes_t n = 0; n < fi_limit; ++n) { mixdown_buffer[n] *= gain_buffer[n]; } } @@ -409,40 +410,40 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff /* fade out */ if (_flags & FadeOut) { - + /* see if some part of this read is within the fade out */ /* ................. >| REGION - _length + limit { } FADE fade_out_length ^ - _length - fade_out_length + limit - fade_out_length |--------------| ^internal_offset ^internal_offset + to_read we need the intersection of [internal_offset,internal_offset+to_read] with - [_length - fade_out_length, _length] + [limit - fade_out_length, limit] */ nframes_t fade_out_length = (nframes_t) _fade_out->back()->when; - nframes_t fade_interval_start = max(internal_offset, _length-fade_out_length); - nframes_t fade_interval_end = min(internal_offset + to_read, _length); - + nframes_t fade_interval_start = max(internal_offset, limit-fade_out_length); + nframes_t fade_interval_end = min(internal_offset + to_read, limit); + if (fade_interval_end > fade_interval_start) { /* (part of the) the fade out is in this buffer */ - - nframes_t limit = fade_interval_end - fade_interval_start; - nframes_t curve_offset = fade_interval_start - (_length-fade_out_length); + + nframes_t fo_limit = fade_interval_end - fade_interval_start; + nframes_t curve_offset = fade_interval_start - (limit-fade_out_length); nframes_t fade_offset = fade_interval_start - internal_offset; - _fade_out->curve().get_vector (curve_offset,curve_offset+limit, gain_buffer, limit); - - for (nframes_t n = 0, m = fade_offset; n < limit; ++n, ++m) { + _fade_out->curve().get_vector (curve_offset, curve_offset+fo_limit, gain_buffer, fo_limit); + + for (nframes_t n = 0, m = fade_offset; n < fo_limit; ++n, ++m) { mixdown_buffer[m] *= gain_buffer[n]; } } @@ -1020,7 +1021,6 @@ AudioRegion::read_raw_internal (Sample* buf, nframes_t pos, nframes_t cnt) const return audio_source()->read (buf, pos, cnt); } - int AudioRegion::exportme (Session& session, ARDOUR::ExportSpecification& spec) { diff --git a/libs/ardour/caimportable.cc b/libs/ardour/caimportable.cc new file mode 100644 index 0000000000..229bfa8809 --- /dev/null +++ b/libs/ardour/caimportable.cc @@ -0,0 +1,118 @@ +#include <ardour/caimportable.h> +#include <sndfile.h> +#include <pbd/error.h> + +#include "i18n.h" + +using namespace ARDOUR; +using namespace std; +using namespace PBD; + +CAImportableSource::CAImportableSource (const string& path) +{ + try { + af.Open (path.c_str()); + + CAStreamBasicDescription file_format (af.GetFileDataFormat()); + CAStreamBasicDescription client_format (file_format); + + /* set canonial form (PCM, native float packed, 32 bit, with the correct number of channels + and interleaved (since we plan to deinterleave ourselves) + */ + + client_format.SetCanonical(client_format.NumberChannels(), true); + af.SetClientFormat (client_format); + + } catch (CAXException& cax) { + error << string_compose ("CAImportable: %1", cax.mOperation) << endmsg; + throw failed_constructor (); + } + +} + +CAImportableSource::~CAImportableSource () +{ +} + +nframes_t +CAImportableSource::read (Sample* buffer, nframes_t nframes) +{ + nframes_t nread = 0; + AudioBufferList abl; + nframes_t per_channel; + bool at_end = false; + + abl.mNumberBuffers = 1; + abl.mBuffers[0].mNumberChannels = channels(); + + per_channel = nframes / abl.mBuffers[0].mNumberChannels; + + while (nread < per_channel) { + + UInt32 new_cnt = per_channel - nread; + + abl.mBuffers[0].mDataByteSize = new_cnt * abl.mBuffers[0].mNumberChannels * sizeof(Sample); + abl.mBuffers[0].mData = buffer + nread; + + try { + af.Read (new_cnt, &abl); + } catch (CAXException& cax) { + error << string_compose("CAImportable: %1", cax.mOperation); + return -1; + } + + if (new_cnt == 0) { + /* EOF */ + at_end = true; + break; + } + + nread += new_cnt; + } + + if (!at_end && nread < per_channel) { + return 0; + } else { + return nread * abl.mBuffers[0].mNumberChannels; + } +} + +uint +CAImportableSource::channels () const +{ + return af.GetFileDataFormat().NumberChannels(); +} + +nframes_t +CAImportableSource::length () const +{ + return af.GetNumberFrames(); +} + +nframes_t +CAImportableSource::samplerate() const +{ + CAStreamBasicDescription client_asbd; + + try { + client_asbd = af.GetClientDataFormat (); + } catch (CAXException& cax) { + error << string_compose ("CAImportable: %1", cax.mOperation) << endmsg; + return 0.0; + } + + return client_asbd.mSampleRate; +} + +void +CAImportableSource::seek (nframes_t pos) +{ + try { + af.Seek (pos); + } catch (CAXException& cax) { + error << string_compose ("CAImportable: %1 to %2", cax.mOperation, pos) << endmsg; + } +} + + + diff --git a/libs/ardour/coreaudiosource.cc b/libs/ardour/coreaudiosource.cc index 703225e502..4383f1a696 100644 --- a/libs/ardour/coreaudiosource.cc +++ b/libs/ardour/coreaudiosource.cc @@ -1,5 +1,6 @@ /* - Copyright (C) 2006 Paul Davis + Copyright (C) 2006 Paul Davis + Written by Taybin Rutkin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,6 +18,8 @@ */ +#include <algorithm> + #include <pbd/error.h> #include <ardour/coreaudiosource.h> #include <ardour/utils.h> @@ -28,6 +31,7 @@ #include <AudioToolbox/AudioFormat.h> +using namespace std; using namespace ARDOUR; using namespace PBD; @@ -48,18 +52,12 @@ CoreAudioSource::CoreAudioSource (Session& s, const string& path, int chn, Flag void CoreAudioSource::init () { - tmpbuf = 0; - tmpbufsize = 0; - - cerr << "CoreAudioSource::init() " << name() << endl; - /* note that we temporarily truncated _id at the colon */ try { af.Open(_path.c_str()); - CAStreamBasicDescription file_asbd (af.GetFileDataFormat()); - n_channels = file_asbd.NumberChannels(); - cerr << "number of channels: " << n_channels << endl; + CAStreamBasicDescription file_format (af.GetFileDataFormat()); + n_channels = file_format.NumberChannels(); if (_channel >= n_channels) { error << string_compose("CoreAudioSource: file only contains %1 channels; %2 is invalid as a channel number (%3)", n_channels, _channel, name()) << endmsg; @@ -68,92 +66,136 @@ CoreAudioSource::init () _length = af.GetNumberFrames(); - CAStreamBasicDescription client_asbd(file_asbd); - client_asbd.SetCanonical(client_asbd.NumberChannels(), false); - af.SetClientFormat (client_asbd); + CAStreamBasicDescription client_format (file_format); + + /* set canonial form (PCM, native float packed, 32 bit, with the correct number of channels + and interleaved (since we plan to deinterleave ourselves) + */ + + client_format.SetCanonical(client_format.NumberChannels(), true); + af.SetClientFormat (client_format); + } catch (CAXException& cax) { - error << string_compose ("CoreAudioSource: %1 (%2)", cax.mOperation, name()) << endmsg; + + error << string_compose(_("CoreAudioSource: cannot open file \"%1\" for %2"), + _path, (writable() ? "read+write" : "reading")) << endmsg; throw failed_constructor (); } } CoreAudioSource::~CoreAudioSource () { - cerr << "CoreAudioSource::~CoreAudioSource() " << name() << endl; GoingAway (); /* EMIT SIGNAL */ - - if (tmpbuf) { - delete [] tmpbuf; - } - - cerr << "deletion done" << endl; } -nframes_t -CoreAudioSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const +int +CoreAudioSource::safe_read (Sample* dst, nframes_t start, nframes_t cnt, AudioBufferList& abl) const { - try { - af.Seek (start); - } catch (CAXException& cax) { - error << string_compose("CoreAudioSource: %1 to %2 (%3)", cax.mOperation, start, _name.substr (1)) << endmsg; - return 0; - } - - AudioBufferList abl; - abl.mNumberBuffers = 1; - abl.mBuffers[0].mNumberChannels = n_channels; + nframes_t nread = 0; - UInt32 new_cnt = cnt; - if (n_channels == 1) { - abl.mBuffers[0].mDataByteSize = cnt * sizeof(Sample); - abl.mBuffers[0].mData = dst; + while (nread < cnt) { + + try { + af.Seek (start+nread); + } catch (CAXException& cax) { + error << string_compose("CoreAudioSource: %1 to %2 (%3)", cax.mOperation, start+nread, _name.substr (1)) << endmsg; + return -1; + } + + UInt32 new_cnt = cnt - nread; + + abl.mBuffers[0].mDataByteSize = new_cnt * n_channels * sizeof(Sample); + abl.mBuffers[0].mData = dst + nread; + try { af.Read (new_cnt, &abl); } catch (CAXException& cax) { error << string_compose("CoreAudioSource: %1 (%2)", cax.mOperation, _name); + return -1; } - _read_data_count = new_cnt * sizeof(float); - return new_cnt; - } - - UInt32 real_cnt = cnt * n_channels; - { - Glib::Mutex::Lock lm (_tmpbuf_lock); - - if (tmpbufsize < real_cnt) { - - if (tmpbuf) { - delete [] tmpbuf; + if (new_cnt == 0) { + /* EOF */ + if (start+cnt == _length) { + /* we really did hit the end */ + nread = cnt; } - tmpbufsize = real_cnt; - tmpbuf = new float[tmpbufsize]; + break; } - abl.mBuffers[0].mDataByteSize = tmpbufsize * sizeof(Sample); - abl.mBuffers[0].mData = tmpbuf; + nread += new_cnt; + } - cerr << "channel: " << _channel << endl; + if (nread < cnt) { + return -1; + } else { + return 0; + } +} + + +nframes_t +CoreAudioSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const +{ + nframes_t file_cnt; + AudioBufferList abl; + + abl.mNumberBuffers = 1; + abl.mBuffers[0].mNumberChannels = n_channels; + + if (start > _length) { + + /* read starts beyond end of data, just memset to zero */ - try { - af.Read (real_cnt, &abl); - } catch (CAXException& cax) { - error << string_compose("CoreAudioSource: %1 (%2)", cax.mOperation, _name); - } - float *ptr = tmpbuf + _channel; - real_cnt /= n_channels; + file_cnt = 0; + + } else if (start + cnt > _length) { - /* stride through the interleaved data */ + /* read ends beyond end of data, read some, memset the rest */ + + file_cnt = _length - start; + + } else { - for (uint32_t n = 0; n < real_cnt; ++n) { - dst[n] = *ptr; - ptr += n_channels; + /* read is entirely within data */ + + file_cnt = cnt; + } + + if (file_cnt != cnt) { + nframes_t delta = cnt - file_cnt; + memset (dst+file_cnt, 0, sizeof (Sample) * delta); + } + + if (file_cnt) { + + if (n_channels == 1) { + if (safe_read (dst, start, file_cnt, abl) == 0) { + _read_data_count = cnt * sizeof (Sample); + return cnt; + } + return 0; } } + Sample* interleave_buf = get_interleave_buffer (file_cnt * n_channels); + + if (safe_read (interleave_buf, start, file_cnt, abl) != 0) { + return 0; + } + _read_data_count = cnt * sizeof(float); - - return real_cnt; + + Sample *ptr = interleave_buf + _channel; + + /* stride through the interleaved data */ + + for (uint32_t n = 0; n < file_cnt; ++n) { + dst[n] = *ptr; + ptr += n_channels; + } + + return cnt; } float diff --git a/libs/ardour/crossfade.cc b/libs/ardour/crossfade.cc index f7711b3224..f3dfa28165 100644 --- a/libs/ardour/crossfade.cc +++ b/libs/ardour/crossfade.cc @@ -84,7 +84,7 @@ Crossfade::Crossfade (boost::shared_ptr<AudioRegion> in, boost::shared_ptr<Audio { _in = in; _out = out; - + _anchor_point = ap; _follow_overlap = false; diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index 02c4a5ced6..9a71303927 100644 --- a/libs/ardour/globals.cc +++ b/libs/ardour/globals.cc @@ -412,6 +412,21 @@ ARDOUR::get_ardour_revision () return "$Rev$"; } +static bool sae_binding_filter (const string& str, void* arg) +{ + /* Not a dotfile, has a prefix before a period, suffix is ".bindings" and contains -sae- */ + + return str[0] != '.' && str.length() > 13 && str.find (".bindings") == (str.length() - 9) + && str.find ("SAE-") != string::npos; +} + +static bool binding_filter (const string& str, void* arg) +{ + /* Not a dotfile, has a prefix before a period, suffix is ".bindings" */ + + return str[0] != '.' && str.length() > 9 && str.find (".bindings") == (str.length() - 9); +} + void ARDOUR::find_bindings_files (map<string,string>& files) { diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc index a0266521d4..a29cc1817b 100644 --- a/libs/ardour/import.cc +++ b/libs/ardour/import.cc @@ -48,26 +48,66 @@ #include <ardour/region_factory.h> #include <ardour/source_factory.h> #include <ardour/resampled_source.h> +#include <ardour/sndfileimportable.h> #include <ardour/analyser.h> #include <ardour/smf_reader.h> #include <ardour/smf_source.h> #include <ardour/tempo.h> +#ifdef HAVE_COREAUDIO +#include <ardour/caimportable.h> +#endif + #include "i18n.h" using namespace ARDOUR; using namespace PBD; -static std::auto_ptr<ImportableSource> + +static boost::shared_ptr<ImportableSource> open_importable_source (const string& path, nframes_t samplerate, ARDOUR::SrcQuality quality) { - std::auto_ptr<ImportableSource> source(new ImportableSource(path)); +#ifdef HAVE_COREAUDIO - if (source->samplerate() == samplerate) { - return source; - } + /* see if we can use CoreAudio to handle the IO */ - return std::auto_ptr<ImportableSource>(new ResampledImportableSource(path, samplerate, quality)); + try { + boost::shared_ptr<CAImportableSource> source(new CAImportableSource(path)); + + if (source->samplerate() == samplerate) { + return source; + } + + /* rewrap as a resampled source */ + + return boost::shared_ptr<ImportableSource>(new ResampledImportableSource(source, samplerate, quality)); + } + + catch (...) { + + /* fall back to SndFile */ + +#endif + + try { + boost::shared_ptr<SndFileImportableSource> source(new SndFileImportableSource(path)); + + if (source->samplerate() == samplerate) { + return source; + } + + /* rewrap as a resampled source */ + + return boost::shared_ptr<ImportableSource>(new ResampledImportableSource(source, samplerate, quality)); + } + + catch (...) { + throw; // rethrow + } + +#ifdef HAVE_COREAUDIO + } +#endif } static std::string @@ -306,7 +346,7 @@ write_midi_data_to_new_files (SMFReader* source, Session::import_status& status, smfs->session().engine().frame_rate(), smfs->session().tempo_map().meter_at(timeline_position)); - smfs->update_length(0, (t * source->ppqn()) * frames_per_beat); + smfs->update_length(0, (nframes_t) floor ((t * source->ppqn()) * frames_per_beat)); smfs->flush_header(); smfs->flush_footer(); @@ -345,26 +385,24 @@ Session::import_audiofiles (import_status& status) p != status.paths.end() && !status.cancel; ++p, ++cnt) { - std::auto_ptr<ImportableSource> source; + + boost::shared_ptr<ImportableSource> source; std::auto_ptr<SMFReader> smf_reader; + const DataType type = ((*p).rfind(".mid") != string::npos) ? + DataType::MIDI : DataType::AUDIO; - const DataType type = ((*p).rfind(".mid") != string::npos) - ? DataType::MIDI : DataType::AUDIO; - if (type == DataType::AUDIO) { - try - { + try { source = open_importable_source (*p, frame_rate(), status.quality); channels = source->channels(); - } catch (const failed_constructor& err) - { + } catch (const failed_constructor& err) { error << string_compose(_("Import: cannot open input sound file \"%1\""), (*p)) << endmsg; status.done = status.cancel = true; return; } + } else { - try - { + try { smf_reader = std::auto_ptr<SMFReader>(new SMFReader(*p)); channels = smf_reader->num_tracks(); } catch (const SMFReader::UnsupportedTime& err) { @@ -378,11 +416,9 @@ Session::import_audiofiles (import_status& status) } } - vector<string> new_paths = get_paths_for_new_sources (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, + get_best_session_directory_for_new_source (), + channels); Sources newfiles; if (status.replace_existing_source) { @@ -403,9 +439,9 @@ Session::import_audiofiles (import_status& status) } } - if (source.get()) { // audio + if (source) { // audio status.doing_what = compose_status_message (*p, source->samplerate(), - frame_rate(), cnt, status.paths.size()); + frame_rate(), cnt, status.paths.size()); write_audio_data_to_new_files (source.get(), status, newfiles); } else if (smf_reader.get()) { // midi status.doing_what = string_compose(_("loading MIDI file %1"), *p); diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index f57d5b39de..cb9fedd7a3 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -2119,9 +2119,8 @@ IO::setup_peak_meters() void IO::update_meters() { - Glib::Mutex::Lock guard (m_meter_signal_lock); - - Meter(); /* EMIT SIGNAL */ + Glib::Mutex::Lock guard (m_meter_signal_lock); + Meter(); /* EMIT SIGNAL */ } void diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc index 7bc4287a58..f1818420ed 100644 --- a/libs/ardour/playlist.cc +++ b/libs/ardour/playlist.cc @@ -331,7 +331,6 @@ Playlist::release_notifications () } } - void Playlist::notify_modified () { @@ -676,53 +675,64 @@ Playlist::partition (nframes_t start, nframes_t end, bool just_top_level) void Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist) { - RegionLock rlock (this); - boost::shared_ptr<Region> region; - boost::shared_ptr<Region> current; - string new_name; - RegionList::iterator tmp; - OverlapType overlap; - nframes_t pos1, pos2, pos3, pos4; RegionList new_regions; - in_partition = true; - - /* need to work from a copy, because otherwise the regions we add during the process - get operated on as well. - */ - - RegionList copy = regions; - - for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) { + { + RegionLock rlock (this); + boost::shared_ptr<Region> region; + boost::shared_ptr<Region> current; + string new_name; + RegionList::iterator tmp; + OverlapType overlap; + nframes_t pos1, pos2, pos3, pos4; - tmp = i; - ++tmp; - - current = *i; + in_partition = true; - if (current->first_frame() == start && current->last_frame() == end) { - if (cutting) { - remove_region_internal (current); - } - continue; - } + /* need to work from a copy, because otherwise the regions we add during the process + get operated on as well. + */ - if ((overlap = current->coverage (start, end)) == OverlapNone) { - continue; - } + RegionList copy = regions; - pos1 = current->position(); - pos2 = start; - pos3 = end; - pos4 = current->last_frame(); + for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) { + + tmp = i; + ++tmp; + + current = *i; - if (overlap == OverlapInternal) { + if (current->first_frame() >= start && current->last_frame() < end) { + if (cutting) { + remove_region_internal (current); + } + continue; + } - /* split: we need 3 new regions, the front, middle and end. - cut: we need 2 regions, the front and end. + /* coverage will return OverlapStart if the start coincides + with the end point. we do not partition such a region, + so catch this special case. */ + + if (current->first_frame() >= end) { + continue; + } + + if ((overlap = current->coverage (start, end)) == OverlapNone) { + continue; + } + + pos1 = current->position(); + pos2 = start; + pos3 = end; + pos4 = current->last_frame(); + + if (overlap == OverlapInternal) { - /* + /* split: we need 3 new regions, the front, middle and end. + cut: we need 2 regions, the front and end. + */ + + /* start end ---------------*************************------------ P1 P2 P3 P4 @@ -731,37 +741,37 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi CUT ---------------*****----------------====------------ - */ + */ - if (!cutting) { + if (!cutting) { - /* "middle" ++++++ */ + /* "middle" ++++++ */ + + _session.region_name (new_name, current->name(), false); + region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name, + regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit)); + add_region_internal (region, start); + new_regions.push_back (region); + } + /* "end" ====== */ + _session.region_name (new_name, current->name(), false); - region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name, - regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit)); - add_region_internal (region, start); + region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name, + regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit)); + + add_region_internal (region, end); new_regions.push_back (region); - } - - /* "end" ====== */ - - _session.region_name (new_name, current->name(), false); - region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name, - regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit)); - - add_region_internal (region, end); - new_regions.push_back (region); - - /* "front" ***** */ - current->freeze (); - thawlist.push_back (current); - current->trim_end (pos2, this); - - } else if (overlap == OverlapEnd) { - - /* + /* "front" ***** */ + + current->freeze (); + thawlist.push_back (current); + current->trim_end (pos2, this); + + } else if (overlap == OverlapEnd) { + + /* start end ---------------*************************------------ P1 P2 P4 P3 @@ -769,33 +779,32 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi ---------------**************+++++++++++------------ CUT: ---------------**************----------------------- - - */ - - if (!cutting) { + */ - /* end +++++ */ + if (!cutting) { + + /* end +++++ */ + + _session.region_name (new_name, current->name(), false); + region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(), + Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit)); + add_region_internal (region, start); + new_regions.push_back (region); + } - _session.region_name (new_name, current->name(), false); - region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(), - Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit)); - add_region_internal (region, start); - new_regions.push_back (region); - } - - /* front ****** */ - - current->freeze (); - thawlist.push_back (current); - current->trim_end (pos2, this); - - } else if (overlap == OverlapStart) { - - /* split: we need 2 regions: the front and the end. - cut: just trim current to skip the cut area - */ + /* front ****** */ - /* + current->freeze (); + thawlist.push_back (current); + current->trim_end (pos2, this); + + } else if (overlap == OverlapStart) { + + /* split: we need 2 regions: the front and the end. + cut: just trim current to skip the cut area + */ + + /* start end ---------------*************************------------ P2 P1 P3 P4 @@ -805,31 +814,31 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi CUT: -------------------*********************------------ - */ + */ - if (!cutting) { + if (!cutting) { - /* front **** */ - _session.region_name (new_name, current->name(), false); - region = RegionFactory::create (current, 0, pos3 - pos1, new_name, - regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit)); - add_region_internal (region, pos1); - new_regions.push_back (region); - } - - /* end */ - - current->freeze (); - thawlist.push_back (current); - current->trim_front (pos3, this); - - } else if (overlap == OverlapExternal) { - - /* split: no split required. - cut: remove the region. - */ + /* front **** */ + _session.region_name (new_name, current->name(), false); + region = RegionFactory::create (current, 0, pos3 - pos1, new_name, + regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit)); + add_region_internal (region, pos1); + new_regions.push_back (region); + } + + /* end */ + + current->freeze (); + thawlist.push_back (current); + current->trim_front (pos3, this); + + } else if (overlap == OverlapExternal) { + + /* split: no split required. + cut: remove the region. + */ - /* + /* start end ---------------*************************------------ P2 P1 P3 P4 @@ -839,16 +848,21 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi CUT: ---------------------------------------------------- - */ - - if (cutting) { - remove_region_internal (current); + */ + + if (cutting) { + remove_region_internal (current); + } + new_regions.push_back (current); } - new_regions.push_back (current); } - } + + if (current->first_frame() >= current->last_frame()) { + PBD::stacktrace (cerr); + } - in_partition = false; + in_partition = false; + } for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) { check_dependents (*i, false); diff --git a/libs/ardour/rb_effect.cc b/libs/ardour/rb_effect.cc index 9711e5e4dc..4daf5cb33a 100644 --- a/libs/ardour/rb_effect.cc +++ b/libs/ardour/rb_effect.cc @@ -74,6 +74,9 @@ RBEffect::run (boost::shared_ptr<AudioRegion> region) nframes_t pos = 0; int avail = 0; + // note: this_time_fraction is a ratio of original length. 1.0 = no change, + // 0.5 is half as long, 2.0 is twice as long, etc. + double this_time_fraction = tsr.time_fraction * region->stretch (); double this_pitch_fraction = tsr.pitch_fraction * region->shift (); @@ -81,14 +84,14 @@ RBEffect::run (boost::shared_ptr<AudioRegion> region) (RubberBandStretcher::Options) tsr.opts, this_time_fraction, this_pitch_fraction); - stretcher.setExpectedInputDuration(region->length()); - stretcher.setDebugLevel(1); - tsr.progress = 0.0f; tsr.done = false; uint32_t channels = region->n_channels(); - nframes_t duration = region->length(); + nframes_t duration = region->ancestral_length(); + + stretcher.setExpectedInputDuration(duration); + stretcher.setDebugLevel(1); /* the name doesn't need to be super-precise, but allow for 2 fractional digits just to disambiguate close but not identical FX @@ -149,8 +152,8 @@ RBEffect::run (boost::shared_ptr<AudioRegion> region) if (this_read != this_time) { error << string_compose - (_("tempoize: error reading data from %1"), - nsrcs[i]->name()) << endmsg; + (_("tempoize: error reading data from %1 at %2 (wanted %3, got %4)"), + region->name(), pos + region->position(), this_time, this_read) << endmsg; goto out; } } @@ -187,8 +190,8 @@ RBEffect::run (boost::shared_ptr<AudioRegion> region) if (this_read != this_time) { error << string_compose - (_("tempoize: error reading data from %1"), - nsrcs[i]->name()) << endmsg; + (_("tempoize: error reading data from %1 at %2 (wanted %3, got %4)"), + region->name(), pos + region->position(), this_time, this_read) << endmsg; goto out; } } @@ -257,21 +260,12 @@ RBEffect::run (boost::shared_ptr<AudioRegion> region) /* now reset ancestral data for each new region */ for (vector<boost::shared_ptr<AudioRegion> >::iterator x = results.begin(); x != results.end(); ++x) { - nframes64_t astart = (*x)->ancestral_start(); - nframes64_t alength = (*x)->ancestral_length(); - nframes_t start; - nframes_t length; - - // note: this_time_fraction is a ratio of original length. 1.0 = no change, - // 0.5 is half as long, 2.0 is twice as long, etc. - - float stretch = (*x)->stretch() * (tsr.time_fraction/100.0); - float shift = (*x)->shift() * tsr.pitch_fraction; - - start = (nframes_t) floor (astart + ((astart - (*x)->start()) / stretch)); - length = (nframes_t) floor (alength / stretch); - (*x)->set_ancestral_data (start, length, stretch, shift); + (*x)->set_ancestral_data (region->ancestral_start(), + region->ancestral_length(), + this_time_fraction, + this_pitch_fraction ); + (*x)->set_master_sources (region->get_master_sources()); } out: diff --git a/libs/ardour/resampled_source.cc b/libs/ardour/resampled_source.cc index b5d23fb4a2..083fde95a1 100644 --- a/libs/ardour/resampled_source.cc +++ b/libs/ardour/resampled_source.cc @@ -26,15 +26,14 @@ using namespace ARDOUR; using namespace PBD; -const uint32_t ResampledImportableSource::blocksize = 4096U; +const uint32_t ResampledImportableSource::blocksize = 16384U; -ResampledImportableSource::ResampledImportableSource (const std::string& path, - nframes_t rate, SrcQuality srcq) - : ImportableSource (path) +ResampledImportableSource::ResampledImportableSource (boost::shared_ptr<ImportableSource> src, nframes_t rate, SrcQuality srcq) + : source (src) { int err; - sf_seek (in.get(), 0, SEEK_SET) ; + source->seek (0); /* Initialize the sample rate converter. */ @@ -58,7 +57,7 @@ ResampledImportableSource::ResampledImportableSource (const std::string& path, break; } - if ((src_state = src_new (src_type, sf_info.channels, &err)) == 0) { + if ((src_state = src_new (src_type, source->channels(), &err)) == 0) { error << string_compose(_("Import: src_new() failed : %1"), src_strerror (err)) << endmsg ; throw failed_constructor (); } @@ -70,7 +69,7 @@ ResampledImportableSource::ResampledImportableSource (const std::string& path, src_data.input_frames = 0 ; src_data.data_in = input ; - src_data.src_ratio = ((float) rate) / sf_info.samplerate ; + src_data.src_ratio = ((float) rate) / source->samplerate(); input = new float[blocksize]; } @@ -90,22 +89,22 @@ ResampledImportableSource::read (Sample* output, nframes_t nframes) if (src_data.input_frames == 0) { - src_data.input_frames = ImportableSource::read (input, blocksize); + src_data.input_frames = source->read (input, blocksize); /* The last read will not be a full buffer, so set end_of_input. */ if ((nframes_t) src_data.input_frames < blocksize) { - src_data.end_of_input = SF_TRUE ; + src_data.end_of_input = true; } - src_data.input_frames /= sf_info.channels; - src_data.data_in = input ; + src_data.input_frames /= source->channels(); + src_data.data_in = input; } src_data.data_out = output; if (!src_data.end_of_input) { - src_data.output_frames = nframes / sf_info.channels ; + src_data.output_frames = nframes / source->channels(); } else { src_data.output_frames = src_data.input_frames; } @@ -121,9 +120,9 @@ ResampledImportableSource::read (Sample* output, nframes_t nframes) return 0; } - src_data.data_in += src_data.input_frames_used * sf_info.channels ; + src_data.data_in += src_data.input_frames_used * source->channels(); src_data.input_frames -= src_data.input_frames_used ; - return src_data.output_frames_gen * sf_info.channels; + return src_data.output_frames_gen * source->channels(); } diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 560946d9da..85e849de2e 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -828,7 +828,7 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* if ((pi = boost::dynamic_pointer_cast<PluginInsert>(processor)) != 0) { pi->set_count (1); - + if (pi->natural_input_streams() == ChanCount::ZERO) { /* generator plugin */ _have_internal_generator = true; @@ -1198,6 +1198,8 @@ Route::_reset_plugin_counts (ProcessorStreams* err) ProcessorList::iterator r; map<Placement,list<ProcessorCount> > processor_map; ChanCount initial_streams; + ChanCount post_fader_input; + int ret = -1; /* Process each placement in order, checking to see if we can really do what has been requested. @@ -1205,7 +1207,8 @@ Route::_reset_plugin_counts (ProcessorStreams* err) /* divide processors up by placement so we get the signal flow properly modelled. we need to do this because the _processors - list is not sorted by placement + list is not sorted by placement, and because other reasons may + exist now or in the future for this separate treatment. */ /* ... but it should/will be... */ @@ -1219,19 +1222,18 @@ Route::_reset_plugin_counts (ProcessorStreams* err) } } - /* A: PreFader */ if ( ! check_some_plugin_counts (processor_map[PreFader], n_inputs (), err)) { - return -1; + goto streamcount; } - ChanCount post_fader_input = (err ? err->count : n_inputs()); + post_fader_input = (err ? err->count : n_inputs()); /* B: PostFader */ if ( ! check_some_plugin_counts (processor_map[PostFader], post_fader_input, err)) { - return -1; + goto streamcount; } /* OK, everything can be set up correctly, so lets do it */ @@ -1241,15 +1243,15 @@ Route::_reset_plugin_counts (ProcessorStreams* err) /* recompute max outs of any processor */ + ret = 0; + + streamcount: processor_max_outs.reset(); - ProcessorList::iterator prev = _processors.end(); - for (r = _processors.begin(); r != _processors.end(); prev = r, ++r) { + for (r = _processors.begin(); r != _processors.end(); ++r) { processor_max_outs = max ((*r)->output_streams (), processor_max_outs); } - /* we're done */ - return 0; } diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index ae41f3c0dc..71d7a07748 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -431,14 +431,13 @@ Session::destroy () tmp = i; ++tmp; - + i->second->drop_references (); - + i = tmp; } - sources.clear (); - + #ifdef TRACK_DESTRUCTION cerr << "delete mix groups\n"; #endif /* TRACK_DESTRUCTION */ @@ -684,7 +683,7 @@ Session::when_engine_running () add_bundle (c); } - BootMessage (_("Connect ports")); + BootMessage (_("Setup signal flow and plugins")); hookup_io (); @@ -2835,6 +2834,8 @@ Session::remove_source (boost::weak_ptr<Source> src) return; } + cerr << "remove source for " << source->name() << endl; + { Glib::Mutex::Lock lm (source_lock); @@ -4165,7 +4166,7 @@ Session::get_silent_buffers (ChanCount count) _silent_buffers->set_count(count); for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { - for (size_t i=0; i < count.get(*t); ++i) { + for (size_t i= 0; i < count.get(*t); ++i) { _silent_buffers->get(*t, i).clear(); } } diff --git a/libs/ardour/session_butler.cc b/libs/ardour/session_butler.cc index ccbc08248d..872f97eab9 100644 --- a/libs/ardour/session_butler.cc +++ b/libs/ardour/session_butler.cc @@ -29,6 +29,7 @@ #include <pbd/error.h> #include <pbd/pthread_utils.h> +#include <pbd/stacktrace.h> #include <ardour/configuration.h> #include <ardour/audioengine.h> @@ -130,6 +131,7 @@ Session::summon_butler () { char c = ButlerRequest::Run; ::write (butler_request_pipe[1], &c, 1); + // PBD::stacktrace (cerr); } void diff --git a/libs/ardour/session_events.cc b/libs/ardour/session_events.cc index f1355b331b..5fc8cd7535 100644 --- a/libs/ardour/session_events.cc +++ b/libs/ardour/session_events.cc @@ -355,7 +355,8 @@ Session::process_event (Event* ev) case Event::LocateRollLocate: // locate is handled by ::request_roll_at_and_return() _requested_return_frame = ev->target_frame; - set_transport_speed (ev->speed, true); + cerr << "Set RRF " << ev->target_frame << endl; + request_locate (ev->target2_frame, true); break; diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index c4448640fd..70abd01a72 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -1741,7 +1741,8 @@ Session::XMLSourceFactory (const XMLNode& node) } try { - return SourceFactory::create (*this, node); + /* note: do peak building in another thread when loading session state */ + return SourceFactory::create (*this, node, true); } catch (failed_constructor& err) { diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index e6318f5503..8001b87204 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -415,6 +415,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) do_locate = true; } else { _transport_frame = last_stop_frame; + _requested_return_frame = -1; } if (synced_to_jack() && !play_loop) { @@ -451,7 +452,18 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) } #endif - last_stop_frame = _transport_frame; + if (_requested_return_frame < 0) { + last_stop_frame = _transport_frame; + } else { + last_stop_frame = _requested_return_frame; + _requested_return_frame = -1; + } + +/* MISSING IN 3.0 ... move into realtime_stop() */ +// send_full_time_code (); +// deliver_mmc (MIDI::MachineControl::cmdStop, 0); +// deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame); +/* END WHY */ if (did_record) { @@ -1226,8 +1238,8 @@ Session::setup_auto_play () void Session::request_roll_at_and_return (nframes_t start, nframes_t return_to) { - request_locate (start, false); Event *ev = new Event (Event::LocateRollLocate, Event::Add, Event::Immediate, return_to, 1.0); + ev->target2_frame = start; queue_event (ev); } diff --git a/libs/ardour/sndfileimportable.cc b/libs/ardour/sndfileimportable.cc new file mode 100644 index 0000000000..eb0e8a8afb --- /dev/null +++ b/libs/ardour/sndfileimportable.cc @@ -0,0 +1,47 @@ +#include <ardour/sndfileimportable.h> +#include <sndfile.h> + +using namespace ARDOUR; +using namespace std; + +SndFileImportableSource::SndFileImportableSource (const string& path) + : in (sf_open (path.c_str(), SFM_READ, &sf_info), sf_close) +{ + if (!in) throw failed_constructor(); +} + +SndFileImportableSource::~SndFileImportableSource () +{ +} + +nframes_t +SndFileImportableSource::read (Sample* buffer, nframes_t nframes) +{ + nframes_t per_channel = nframes / sf_info.channels; + per_channel = sf_readf_float (in.get(), buffer, per_channel); + return per_channel * sf_info.channels; +} + +uint +SndFileImportableSource::channels () const +{ + return sf_info.channels; +} + +nframes_t +SndFileImportableSource::length () const +{ + return sf_info.frames; +} + +nframes_t +SndFileImportableSource::samplerate() const +{ + return sf_info.samplerate; +} + +void +SndFileImportableSource::seek (nframes_t pos) +{ + sf_seek (in.get(), 0, SEEK_SET); +} diff --git a/libs/ardour/sndfilesource.cc b/libs/ardour/sndfilesource.cc index 7c4859aa55..e534964343 100644 --- a/libs/ardour/sndfilesource.cc +++ b/libs/ardour/sndfilesource.cc @@ -25,7 +25,6 @@ #include <sys/stat.h> #include <glibmm/miscutils.h> -#include <glibmm/thread.h> #include <ardour/sndfilesource.h> #include <ardour/sndfile_helpers.h> #include <ardour/utils.h> @@ -44,22 +43,6 @@ const AudioFileSource::Flag SndFileSource::default_writable_flags = AudioFileSou AudioFileSource::Removable| AudioFileSource::RemovableIfEmpty| AudioFileSource::CanRename); - -struct SizedSampleBuffer { - nframes_t size; - Sample* buf; - - SizedSampleBuffer (nframes_t sz) : size (sz) { - buf = new Sample[size]; - } - - ~SizedSampleBuffer() { - delete [] buf; - } -}; - -Glib::StaticPrivate<SizedSampleBuffer> thread_interleave_buffer = GLIBMM_STATIC_PRIVATE_INIT; - SndFileSource::SndFileSource (Session& s, const XMLNode& node) : AudioFileSource (s, node) { @@ -95,7 +78,7 @@ SndFileSource::SndFileSource (Session& s, ustring path, SampleFormat sfmt, Heade */ file_is_new = true; - + switch (hf) { case CAF: fmt = SF_FORMAT_CAF; @@ -189,9 +172,8 @@ SndFileSource::SndFileSource (Session& s, ustring path, SampleFormat sfmt, Heade _flags = Flag (_flags & ~Broadcast); delete _broadcast_info; _broadcast_info = 0; - } - - } + } + } } void @@ -234,13 +216,21 @@ SndFileSource::open () if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) { char errbuf[256]; sf_error_str (0, errbuf, sizeof (errbuf) - 1); +#ifndef HAVE_COREAUDIO + /* if we have CoreAudio, we will be falling back to that if libsndfile fails, + so we don't want to see this message. + */ + error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"), _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg; +#endif return -1; } if (_channel >= _info.channels) { +#ifndef HAVE_COREAUDIO error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg; +#endif sf_close (sf); sf = 0; return -1; @@ -255,7 +245,7 @@ SndFileSource::open () set_timeline_position (get_timecode_info (sf, _broadcast_info, timecode_info_exists)); - if (!timecode_info_exists) { + if (_length != 0 && !timecode_info_exists) { delete _broadcast_info; _broadcast_info = 0; _flags = Flag (_flags & ~Broadcast); @@ -327,6 +317,11 @@ SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const file_cnt = cnt; } + if (file_cnt != cnt) { + nframes_t delta = cnt - file_cnt; + memset (dst+file_cnt, 0, sizeof (Sample) * delta); + } + if (file_cnt) { if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) { @@ -343,11 +338,6 @@ SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const } } - if (file_cnt != cnt) { - nframes_t delta = cnt - file_cnt; - memset (dst+file_cnt, 0, sizeof (Sample) * delta); - } - real_cnt = cnt * _info.channels; Sample* interleave_buf = get_interleave_buffer (real_cnt); @@ -907,20 +897,3 @@ SndFileSource::one_of_several_channels () const return _info.channels > 1; } -Sample* -SndFileSource::get_interleave_buffer (nframes_t size) -{ - SizedSampleBuffer* ssb; - - if ((ssb = thread_interleave_buffer.get()) == 0) { - ssb = new SizedSampleBuffer (size); - thread_interleave_buffer.set (ssb); - } - - if (ssb->size < size) { - ssb = new SizedSampleBuffer (size); - thread_interleave_buffer.set (ssb); - } - - return ssb->buf; -} diff --git a/libs/ardour/source_factory.cc b/libs/ardour/source_factory.cc index 804d4a4d47..5338997659 100644 --- a/libs/ardour/source_factory.cc +++ b/libs/ardour/source_factory.cc @@ -21,6 +21,7 @@ #include <pbd/error.h> #include <pbd/convert.h> #include <pbd/pthread_utils.h> +#include <pbd/stacktrace.h> #include <ardour/source_factory.h> #include <ardour/sndfilesource.h> @@ -28,10 +29,15 @@ #include <ardour/configuration.h> #include <ardour/smf_source.h> -#ifdef HAVE_COREAUDIO +#ifdef HAVE_COREAUDIO +#define USE_COREAUDIO_FOR_FILES +#endif + +#ifdef USE_COREAUDIO_FOR_FILES #include <ardour/coreaudiosource.h> #endif + #include "i18n.h" using namespace ARDOUR; @@ -68,6 +74,7 @@ peak_thread_work () if (!as) { continue; } + as->setup_peakfile (); } } @@ -128,48 +135,36 @@ SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks) if (type == DataType::AUDIO) { -#ifdef HAVE_COREAUDIO - try { - boost::shared_ptr<Source> ret (new CoreAudioSource (s, node)); - + + boost::shared_ptr<Source> ret (new SndFileSource (s, node)); if (setup_peakfile (ret, defer_peaks)) { return boost::shared_ptr<Source>(); } - ret->check_for_analysis_data_on_disk (); SourceCreated (ret); return ret; } - - + catch (failed_constructor& err) { +#ifdef USE_COREAUDIO_FOR_FILES + /* this is allowed to throw */ - - boost::shared_ptr<Source> ret (new SndFileSource (s, node)); - + + boost::shared_ptr<Source> ret (new CoreAudioSource (s, node)); + if (setup_peakfile (ret, defer_peaks)) { return boost::shared_ptr<Source>(); } - + ret->check_for_analysis_data_on_disk (); SourceCreated (ret); return ret; - } #else - /* this is allowed to throw */ - - boost::shared_ptr<Source> ret (new SndFileSource (s, node)); - - if (setup_peakfile (ret, defer_peaks)) { - return boost::shared_ptr<Source>(); - } - - ret->check_for_analysis_data_on_disk (); - SourceCreated (ret); - return ret; + throw; // rethrow #endif + } } else if (type == DataType::MIDI) { boost::shared_ptr<Source> ret (new SMFSource (s, node)); @@ -185,59 +180,57 @@ boost::shared_ptr<Source> SourceFactory::createReadable (DataType type, Session& s, string path, int chn, AudioFileSource::Flag flags, bool announce, bool defer_peaks) { if (type == DataType::AUDIO) { - -#ifdef HAVE_COREAUDIO - try { - boost::shared_ptr<Source> ret (new CoreAudioSource (s, path, chn, flags)); - - if (setup_peakfile (ret, defer_peaks)) { - return boost::shared_ptr<Source>(); - } - ret->check_for_analysis_data_on_disk (); - if (announce) { - SourceCreated (ret); - } - return ret; - } - - catch (failed_constructor& err) { - boost::shared_ptr<Source> ret (new SndFileSource (s, path, chn, flags)); - if (setup_peakfile (ret, defer_peaks)) { - return boost::shared_ptr<Source>(); + if (!(flags & Destructive)) { + + try { + + boost::shared_ptr<Source> ret (new SndFileSource (s, path, chn, flags)); + + if (setup_peakfile (ret, defer_peaks)) { + return boost::shared_ptr<Source>(); + } + + ret->check_for_analysis_data_on_disk (); + if (announce) { + SourceCreated (ret); + } + return ret; } - ret->check_for_analysis_data_on_disk (); - if (announce) { - SourceCreated (ret); - } - return ret; - } + + catch (failed_constructor& err) { +#ifdef USE_COREAUDIO_FOR_FILES + + boost::shared_ptr<Source> ret (new CoreAudioSource (s, path, chn, flags)); + if (setup_peakfile (ret, defer_peaks)) { + return boost::shared_ptr<Source>(); + } + ret->check_for_analysis_data_on_disk (); + if (announce) { + SourceCreated (ret); + } + return ret; + #else - boost::shared_ptr<Source> ret (new SndFileSource (s, path, chn, flags)); - - if (setup_peakfile (ret, defer_peaks)) { - return boost::shared_ptr<Source>(); - } + throw; // rethrow +#endif + } - ret->check_for_analysis_data_on_disk (); - if (announce) { - SourceCreated (ret); + } else { + // eh? } - - return ret; -#endif - + } else if (type == DataType::MIDI) { - + // FIXME: flags? boost::shared_ptr<Source> ret (new SMFSource (s, path, SMFSource::Flag(0))); - - ret->check_for_analysis_data_on_disk (); + if (announce) { SourceCreated (ret); } return ret; + } return boost::shared_ptr<Source>(); diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc index bcbb01d9c9..ab7b7c096e 100644 --- a/libs/ardour/tempo.cc +++ b/libs/ardour/tempo.cc @@ -1178,11 +1178,12 @@ TempoMap::round_to_type (nframes_t frame, int dir, BBTPointType type) break; } - + + /* cerr << "for " << frame << " round to " << bbt << " using " << metric.start() << endl; - + */ return metric.frame() + count_frames_between (metric.start(), bbt); } |