diff options
Diffstat (limited to 'libs/ardour')
76 files changed, 2893 insertions, 1633 deletions
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index feb93ec293..7230a0622b 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -34,6 +34,11 @@ audio_library.cc audio_playlist.cc audio_track.cc audioengine.cc +port.cc +audio_port.cc +midi_port.cc +port_set.cc +buffer.cc audiofilesource.cc audiofilter.cc audioregion.cc @@ -72,7 +77,6 @@ playlist.cc playlist_factory.cc plugin.cc plugin_manager.cc -port.cc recent_sessions.cc redirect.cc region.cc diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h index e2dfc5fd0c..0cc2079d8e 100644 --- a/libs/ardour/ardour/audio_diskstream.h +++ b/libs/ardour/ardour/audio_diskstream.h @@ -211,11 +211,11 @@ class AudioDiskstream : public Diskstream /* The two central butler operations */ int do_flush (Session::RunContext context, bool force = false); - int do_refill () { return _do_refill(_mixdown_buffer, _gain_buffer, _conversion_buffer); } + int do_refill () { return _do_refill(_mixdown_buffer, _gain_buffer); } int do_refill_with_alloc(); - int read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, char * workbuf, + int read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, jack_nframes_t& start, jack_nframes_t cnt, ChannelInfo& channel_info, int channel, bool reversed); @@ -251,10 +251,9 @@ class AudioDiskstream : public Diskstream static size_t _working_buffers_size; static Sample* _mixdown_buffer; static gain_t* _gain_buffer; - static char* _conversion_buffer; - // Uh, /really/ private? (death to friend classes) - int _do_refill (Sample *mixdown_buffer, float *gain_buffer, char *workbuf); + // Uh, /really/ private? (there should probably be less friends of Diskstream) + int _do_refill (Sample *mixdown_buffer, float *gain_buffer); std::vector<AudioFileSource*> capturing_sources; diff --git a/libs/ardour/ardour/audio_port.h b/libs/ardour/ardour/audio_port.h new file mode 100644 index 0000000000..1eab294028 --- /dev/null +++ b/libs/ardour/ardour/audio_port.h @@ -0,0 +1,110 @@ +/* + Copyright (C) 2002 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. + + $Id: port.h 712 2006-07-28 01:08:57Z drobilla $ +*/ + +#ifndef __ardour_audio_port_h__ +#define __ardour_audio_port_h__ + +#include <sigc++/signal.h> +#include <pbd/failed_constructor.h> +#include <ardour/ardour.h> +#include <jack/jack.h> +#include <ardour/port.h> +#include <ardour/buffer.h> + +namespace ARDOUR { + +class AudioEngine; + +class AudioPort : public Port { + public: + virtual ~AudioPort() { + free (_port); + } + + void cycle_start(jack_nframes_t nframes); + void cycle_end(); + + DataType type() const { return DataType(DataType::AUDIO); } + + Buffer& get_buffer () { + return _buffer; + } + + AudioBuffer& get_audio_buffer() { + return _buffer; + } + + void reset_overs () { + _short_overs = 0; + _long_overs = 0; + _overlen = 0; + } + + void reset_peak_meter () { + _peak = 0; + } + + void reset_meters () { + reset_peak_meter (); + reset_overs (); + } + + float peak_db() const { return _peak_db; } + jack_default_audio_sample_t peak() const { return _peak; } + + uint32_t short_overs () const { return _short_overs; } + uint32_t long_overs () const { return _long_overs; } + + static void set_short_over_length (jack_nframes_t); + static void set_long_over_length (jack_nframes_t); + + /** Assumes that the port is an audio output port */ + void silence (jack_nframes_t nframes, jack_nframes_t offset) { + if (!_silent) { + _buffer.clear(offset); + if (offset == 0 && nframes == _buffer.capacity()) { + _silent = true; + } + } + } + + protected: + friend class AudioEngine; + + AudioPort (jack_port_t *port); + void reset (); + + /* engine isn't supposed to access below here */ + + AudioBuffer _buffer; + + jack_nframes_t _overlen; + jack_default_audio_sample_t _peak; + float _peak_db; + uint32_t _short_overs; + uint32_t _long_overs; + + static jack_nframes_t _long_over_length; + static jack_nframes_t _short_over_length; +}; + +} // namespace ARDOUR + +#endif /* __ardour_audio_port_h__ */ diff --git a/libs/ardour/ardour/audio_track.h b/libs/ardour/ardour/audio_track.h index 15b99297c8..9892179085 100644 --- a/libs/ardour/ardour/audio_track.h +++ b/libs/ardour/ardour/audio_track.h @@ -51,7 +51,7 @@ class AudioTrack : public Track int use_diskstream (string name); int use_diskstream (const PBD::ID& id); - int export_stuff (vector<Sample*>& buffers, char * workbuf, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t end_frame); + int export_stuff (vector<Sample*>& buffers, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t end_frame); void freeze (InterThreadInfo&); void unfreeze (); diff --git a/libs/ardour/ardour/audio_unit.h b/libs/ardour/ardour/audio_unit.h index 1c8d6cbc2d..348a8ff863 100644 --- a/libs/ardour/ardour/audio_unit.h +++ b/libs/ardour/ardour/audio_unit.h @@ -96,6 +96,8 @@ class AUPlugin : public ARDOUR::Plugin std::vector<std::pair<uint32_t, uint32_t> > parameter_map; }; +typedef boost::shared_ptr<AUPlugin> AUPluginPtr; + class AUPluginInfo : public PluginInfo { public: AUPluginInfo () { }; diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h index e7500fc7a2..72989abb59 100644 --- a/libs/ardour/ardour/audioengine.h +++ b/libs/ardour/ardour/audioengine.h @@ -119,21 +119,19 @@ class AudioEngine : public sigc::trackable uint32_t n_physical_outputs () const; uint32_t n_physical_inputs () const; - std::string get_nth_physical_output (uint32_t n) { - return get_nth_physical (n, JackPortIsInput); + std::string get_nth_physical_output (DataType type, uint32_t n) { + return get_nth_physical (type, n, JackPortIsInput); } - std::string get_nth_physical_input (uint32_t n) { - return get_nth_physical (n, JackPortIsOutput); + std::string get_nth_physical_input (DataType type, uint32_t n) { + return get_nth_physical (type, n, JackPortIsOutput); } jack_nframes_t get_port_total_latency (const Port&); void update_total_latencies (); - /* the caller may not delete the object pointed to by - the return value + /** Caller may not delete the object pointed to by the return value */ - Port *get_port_by_name (const std::string& name, bool keep = true); enum TransportState { @@ -219,7 +217,7 @@ class AudioEngine : public sigc::trackable PortConnections port_connections; void remove_connections_for (Port*); - std::string get_nth_physical (uint32_t which, int flags); + std::string get_nth_physical (DataType type, uint32_t n, int flags); static int _xrun_callback (void *arg); static int _graph_order_callback (void *arg); diff --git a/libs/ardour/ardour/audioplaylist.h b/libs/ardour/ardour/audioplaylist.h index 5a77067f8f..bd76c30289 100644 --- a/libs/ardour/ardour/audioplaylist.h +++ b/libs/ardour/ardour/audioplaylist.h @@ -60,7 +60,7 @@ class AudioPlaylist : public ARDOUR::Playlist void clear (bool with_delete = false, bool with_save = true); - jack_nframes_t read (Sample *dst, Sample *mixdown, float *gain_buffer, char * workbuf, jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n=0); + jack_nframes_t read (Sample *dst, Sample *mixdown, float *gain_buffer, jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n=0); int set_state (const XMLNode&); UndoAction get_memento() const; diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h index 683e946713..fd2cc8d2f1 100644 --- a/libs/ardour/ardour/audioregion.h +++ b/libs/ardour/ardour/audioregion.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2001 Paul Davis + Copyright (C) 2000-2006 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 @@ -57,8 +57,6 @@ struct AudioRegionState : public RegionState class AudioRegion : public Region { public: - typedef vector<AudioSource *> SourceList; - static Change FadeInChanged; static Change FadeOutChanged; static Change FadeInActiveChanged; @@ -76,26 +74,18 @@ class AudioRegion : public Region AudioRegion (SourceList &, const XMLNode&); ~AudioRegion(); - bool source_equivalent (const Region&) const; - bool speed_mismatch (float) const; - void lock_sources (); - void unlock_sources (); - AudioSource& source (uint32_t n=0) const { if (n < sources.size()) return *sources[n]; else return *sources[0]; } + AudioSource& audio_source (uint32_t n=0) const; - void set_scale_amplitude (gain_t); + void set_scale_amplitude (gain_t); gain_t scale_amplitude() const { return _scale_amplitude; } void normalize_to (float target_in_dB = 0.0f); - uint32_t n_channels() { return sources.size(); } - vector<string> master_source_names(); - bool envelope_active () const { return _flags & Region::EnvelopeActive; } bool fade_in_active () const { return _flags & Region::FadeIn; } bool fade_out_active () const { return _flags & Region::FadeOut; } - bool captured() const { return !(_flags & (Region::Flag (Region::Import|Region::External))); } Curve& fade_in() { return _fade_in; } Curve& fade_out() { return _fade_out; } @@ -106,13 +96,12 @@ class AudioRegion : public Region uint32_t chan_n=0, double samples_per_unit= 1.0) const; virtual jack_nframes_t read_at (Sample *buf, Sample *mixdown_buf, - float *gain_buf, char * workbuf, jack_nframes_t position, jack_nframes_t cnt, + float *gain_buf, jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n = 0, jack_nframes_t read_frames = 0, jack_nframes_t skip_frames = 0) const; - jack_nframes_t master_read_at (Sample *buf, Sample *mixdown_buf, - float *gain_buf, char * workbuf, + jack_nframes_t master_read_at (Sample *buf, Sample *mixdown_buf, float *gain_buf, jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n=0) const; XMLNode& state (bool); @@ -152,8 +141,6 @@ class AudioRegion : public Region int exportme (ARDOUR::Session&, ARDOUR::AudioExportSpecification&); - Region* get_parent(); - /* xfade/fade interactions */ void suspend_fade_in (); @@ -177,28 +164,17 @@ class AudioRegion : public Region void recompute_gain_at_start (); jack_nframes_t _read_at (const SourceList&, Sample *buf, Sample *mixdown_buffer, - float *gain_buffer, char * workbuf, jack_nframes_t position, jack_nframes_t cnt, + float *gain_buffer, jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n = 0, jack_nframes_t read_frames = 0, jack_nframes_t skip_frames = 0) const; - bool verify_start (jack_nframes_t position); - bool verify_length (jack_nframes_t position); - bool verify_start_mutable (jack_nframes_t& start); - bool verify_start_and_length (jack_nframes_t start, jack_nframes_t length); void recompute_at_start (); void recompute_at_end (); void envelope_changed (Change); - void source_deleted (Source*); - - SourceList sources; - - /** Used when timefx are applied, so we can always use the original source. */ - SourceList master_sources; - mutable Curve _fade_in; FadeShape _fade_in_shape; mutable Curve _fade_out; diff --git a/libs/ardour/ardour/audiosource.h b/libs/ardour/ardour/audiosource.h index 35158a24e7..4af857c1d6 100644 --- a/libs/ardour/ardour/audiosource.h +++ b/libs/ardour/ardour/audiosource.h @@ -50,24 +50,11 @@ class AudioSource : public Source AudioSource (string name); AudioSource (const XMLNode&); virtual ~AudioSource (); - - /* one could argue that this should belong to Source, but other data types - generally do not come with a model of "offset along an audio timeline" - so its here in AudioSource for now. - */ - - virtual jack_nframes_t natural_position() const { return 0; } - /* returns the number of items in this `audio_source' */ - - virtual jack_nframes_t length() const { - return _length; - } - virtual jack_nframes_t available_peaks (double zoom) const; - virtual jack_nframes_t read (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const; - virtual jack_nframes_t write (Sample *src, jack_nframes_t cnt, char * workbuf); + virtual jack_nframes_t read (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const; + virtual jack_nframes_t write (Sample *src, jack_nframes_t cnt); virtual float sample_rate () const = 0; @@ -111,7 +98,6 @@ class AudioSource : public Source bool _peaks_built; mutable Glib::Mutex _lock; - jack_nframes_t _length; bool next_peak_clear_should_notify; string peakpath; string _captured_for; @@ -124,13 +110,11 @@ class AudioSource : public Source int do_build_peak (jack_nframes_t, jack_nframes_t); - virtual jack_nframes_t read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const = 0; - virtual jack_nframes_t write_unlocked (Sample *dst, jack_nframes_t cnt, char * workbuf) = 0; + virtual jack_nframes_t read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const = 0; + virtual jack_nframes_t write_unlocked (Sample *dst, jack_nframes_t cnt) = 0; virtual string peak_path(string audio_path) = 0; virtual string old_peak_path(string audio_path) = 0; - void update_length (jack_nframes_t pos, jack_nframes_t cnt); - static pthread_t peak_thread; static bool have_peak_thread; static void* peak_thread_work(void*); diff --git a/libs/ardour/ardour/buffer.h b/libs/ardour/ardour/buffer.h index 1321f6c107..981d941de7 100644 --- a/libs/ardour/ardour/buffer.h +++ b/libs/ardour/ardour/buffer.h @@ -19,19 +19,15 @@ #ifndef __ardour_buffer_h__ #define __ardour_buffer_h__ -#define _XOPEN_SOURCE 600 -#include <cstdlib> // for posix_memalign +#include <cstdlib> #include <cassert> +#include <iostream> #include <ardour/types.h> #include <ardour/data_type.h> namespace ARDOUR { -/* Yes, this is a bit of a mess right now. I'll clean it up when everything - * using it works out.. */ - - /** A buffer of recordable/playable data. * * This is a datatype-agnostic base class for all buffers (there are no @@ -44,12 +40,11 @@ namespace ARDOUR { class Buffer { public: - Buffer(DataType type, size_t capacity) - : _type(type), _capacity(capacity), _size(0) - {} - virtual ~Buffer() {} + /** Factory function */ + static Buffer* create(DataType type, size_t capacity); + /** Maximum capacity of buffer. * Note in some cases the entire buffer may not contain valid data, use size. */ size_t capacity() const { return _capacity; } @@ -61,10 +56,24 @@ public: * Based on this you can static cast a Buffer* to the desired type. */ DataType type() const { return _type; } + /** Clear (eg zero, or empty) buffer starting at TIME @a offset */ + virtual void clear(jack_nframes_t offset = 0) = 0; + + virtual void write(const Buffer& src, jack_nframes_t offset, jack_nframes_t len) = 0; + protected: + Buffer(DataType type, size_t capacity) + : _type(type), _capacity(capacity), _size(0) + {} + DataType _type; size_t _capacity; size_t _size; + +private: + // Prevent copies (undefined) + Buffer(const Buffer& copy); + void operator=(const Buffer& other); }; @@ -75,28 +84,51 @@ protected: class AudioBuffer : public Buffer { public: - AudioBuffer(size_t capacity) - : Buffer(DataType::AUDIO, capacity) - , _data(NULL) + AudioBuffer(size_t capacity); + + ~AudioBuffer(); + + void clear(jack_nframes_t offset=0) { memset(_data + offset, 0, sizeof (Sample) * _capacity); } + + /** Copy @a len frames starting at @a offset, from the start of @a src */ + void write(const Buffer& src, jack_nframes_t offset, jack_nframes_t len) + { + assert(src.type() == _type == DataType::AUDIO); + assert(offset + len <= _capacity); + memcpy(_data + offset, ((AudioBuffer&)src).data(len, offset), sizeof(Sample) * len); + } + + /** Copy @a len frames starting at @a offset, from the start of @a src */ + void write(const Sample* src, jack_nframes_t offset, jack_nframes_t len) + { + assert(offset + len <= _capacity); + memcpy(_data + offset, src, sizeof(Sample) * len); + } + + /** Set the data contained by this buffer manually (for setting directly to jack buffer). + * + * Constructor MUST have been passed capacity=0 or this will die (to prevent mem leaks). + */ + void set_data(Sample* data, size_t size) { - _size = capacity; // For audio buffers, size = capacity (always) -#ifdef NO_POSIX_MEMALIGN - _data = (Sample *) malloc(sizeof(Sample) * capacity); -#else - posix_memalign((void**)_data, 16, sizeof(Sample) * capacity); -#endif - assert(_data); - memset(_data, 0, sizeof(Sample) * capacity); + assert(!_owns_data); // prevent leaks + _capacity = size; + _size = size; + _data = data; } - const Sample* data() const { return _data; } - Sample* data() { return _data; } + const Sample* data(jack_nframes_t nframes, jack_nframes_t offset=0) const + { assert(offset + nframes <= _capacity); return _data + offset; } + + Sample* data(jack_nframes_t nframes, jack_nframes_t offset=0) + { assert(offset + nframes <= _capacity); return _data + offset; } private: // These are undefined (prevent copies) AudioBuffer(const AudioBuffer& copy); AudioBuffer& operator=(const AudioBuffer& copy); + bool _owns_data; Sample* _data; ///< Actual buffer contents }; @@ -106,19 +138,16 @@ private: class MidiBuffer : public Buffer { public: - MidiBuffer(size_t capacity) - : Buffer(DataType::MIDI, capacity) - , _data(NULL) - { - _size = capacity; // For audio buffers, size = capacity (always) -#ifdef NO_POSIX_MEMALIGN - _data = (RawMidi *) malloc(sizeof(RawMidi) * capacity); -#else - posix_memalign((void**)_data, 16, sizeof(RawMidi) * capacity); -#endif - assert(_data); - memset(_data, 0, sizeof(RawMidi) * capacity); - } + MidiBuffer(size_t capacity); + + ~MidiBuffer(); + + // FIXME: clear events starting at offset + void clear(jack_nframes_t offset=0) { assert(offset == 0); _size = 0; } + + void write(const Buffer& src, jack_nframes_t offset, jack_nframes_t nframes); + + void set_size(size_t size) { _size = size; } const RawMidi* data() const { return _data; } RawMidi* data() { return _data; } @@ -128,10 +157,10 @@ private: MidiBuffer(const MidiBuffer& copy); MidiBuffer& operator=(const MidiBuffer& copy); + bool _owns_data; RawMidi* _data; ///< Actual buffer contents }; - } // namespace ARDOUR #endif // __ardour_buffer_h__ diff --git a/libs/ardour/ardour/chan_count.h b/libs/ardour/ardour/chan_count.h new file mode 100644 index 0000000000..2ef49793d1 --- /dev/null +++ b/libs/ardour/ardour/chan_count.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2006 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. + + $Id: insert.cc 712 2006-07-28 01:08:57Z drobilla $ +*/ + +#ifndef __ardour_chan_count_h__ +#define __ardour_chan_count_h__ + +#include <ardour/data_type.h> + +namespace ARDOUR { + + +class ChanCount { +public: + ChanCount() { reset(); } + + // Convenience constructor for making single-typed streams (stereo, mono, etc) + ChanCount(DataType type, size_t channels) + { + reset(); + set_count(type, channels); + } + + void reset() + { + for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { + _counts[(*t).to_index()] = 0; + } + } + + void set_count(DataType type, size_t count) { _counts[type.to_index()] = count; } + size_t get_count(DataType type) const { return _counts[type.to_index()]; } + + size_t get_total_count() const + { + size_t ret = 0; + for (size_t i=0; i < DataType::num_types; ++i) + ret += _counts[i]; + + return ret; + } + + bool operator==(const ChanCount& other) const + { + for (size_t i=0; i < DataType::num_types; ++i) + if (_counts[i] != other._counts[i]) + return false; + + return true; + } + + bool operator!=(const ChanCount& other) const + { + return ! (*this == other); + } + +private: + size_t _counts[DataType::num_types]; +}; + + +} // namespace ARDOUR + +#endif // __ardour_chan_count_h__ + diff --git a/libs/ardour/ardour/coreaudiosource.h b/libs/ardour/ardour/coreaudiosource.h index ba9f122fc9..cf25c466ee 100644 --- a/libs/ardour/ardour/coreaudiosource.h +++ b/libs/ardour/ardour/coreaudiosource.h @@ -38,9 +38,9 @@ class CoreAudioSource : public AudioFileSource { void set_header_timeline_position () {}; protected: - jack_nframes_t read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const; + jack_nframes_t read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const; - jack_nframes_t write_unlocked (Sample *dst, jack_nframes_t cnt, char * workbuf) + jack_nframes_t write_unlocked (Sample *dst, jack_nframes_t cnt) { return 0; } diff --git a/libs/ardour/ardour/crossfade.h b/libs/ardour/ardour/crossfade.h index ebafa0e8cc..aea7b31852 100644 --- a/libs/ardour/ardour/crossfade.h +++ b/libs/ardour/ardour/crossfade.h @@ -92,7 +92,7 @@ class Crossfade : public Stateful, public StateManager ARDOUR::AudioRegion& out() const { return *_out; } jack_nframes_t read_at (Sample *buf, Sample *mixdown_buffer, - float *gain_buffer, char * workbuf, jack_nframes_t position, jack_nframes_t cnt, + float *gain_buffer, jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n, jack_nframes_t read_frames = 0, jack_nframes_t skip_frames = 0); diff --git a/libs/ardour/ardour/data_type.h b/libs/ardour/ardour/data_type.h index d49ed108cd..cbb88afccf 100644 --- a/libs/ardour/ardour/data_type.h +++ b/libs/ardour/ardour/data_type.h @@ -19,54 +19,112 @@ #ifndef __ardour_data_type_h__ #define __ardour_data_type_h__ +#include <string> +#include <ardour/data_type.h> #include <jack/jack.h> namespace ARDOUR { + +/** A type of Data Ardour is capable of processing. + * + * The majority of this class is dedicated to conversion to and from various + * other type representations, simple comparison between then, etc. This code + * is deliberately 'ugly' so other code doesn't have to be. + */ class DataType { public: + /// WARNING: make REALLY sure you don't mess up indexes if you change this enum Symbol { NIL = 0, AUDIO, MIDI }; + + /** Number of types (not including NIL). + * WARNING: make sure this matches Symbol! + */ + static const size_t num_types = 2; + + + /** Helper for collections that store typed things by index (BufferSet, PortList). + * Guaranteed to be a valid index from 0 to (the number of available types - 1), + * because NIL is not included. No, this isn't pretty - purely for speed. + * See DataType::to_index(). + */ + inline static size_t symbol_index(const Symbol symbol) + { return (size_t)symbol - 1; } DataType(const Symbol& symbol) : _symbol(symbol) {} - /** Construct from a string (Used for loading from XML) */ - DataType(const string& str) { + /** Construct from a string (Used for loading from XML and Ports) + * The string can be as in an XML file (eg "audio" or "midi"), or a + * Jack type string (from jack_port_type) */ + DataType(const std::string& str) { if (str == "audio") _symbol = AUDIO; - //else if (str == "midi") - // _symbol = MIDI; + else if (str == JACK_DEFAULT_AUDIO_TYPE) + _symbol = AUDIO; + else if (str == "midi") + _symbol = MIDI; + else if (str == JACK_DEFAULT_MIDI_TYPE) + _symbol = MIDI; else _symbol = NIL; } - bool operator==(const Symbol symbol) { return _symbol == symbol; } - bool operator!=(const Symbol symbol) { return _symbol != symbol; } - /** Get the Jack type this DataType corresponds to */ - const char* to_jack_type() { + const char* to_jack_type() const { switch (_symbol) { case AUDIO: return JACK_DEFAULT_AUDIO_TYPE; - //case MIDI: return JACK_DEFAULT_MIDI_TYPE; + case MIDI: return JACK_DEFAULT_MIDI_TYPE; default: return ""; } } /** Inverse of the from-string constructor */ - const char* to_string() { + const char* to_string() const { switch (_symbol) { case AUDIO: return "audio"; - //case MIDI: return "midi"; + case MIDI: return "midi"; default: return "unknown"; // reeeally shouldn't ever happen } } + Symbol to_symbol() const { return _symbol; } + inline size_t to_index() const { return symbol_index(_symbol); } + + /** DataType iterator, for writing generic loops that iterate over all + * available types. + */ + class iterator { + public: + + iterator(size_t index) : _index(index) {} + + DataType operator*() { return DataType((Symbol)_index); } + iterator& operator++() { ++_index; return *this; } // yes, prefix only + bool operator==(const iterator& other) { return (_index == other._index); } + bool operator!=(const iterator& other) { return (_index != other._index); } + + private: + friend class DataType; + + size_t _index; + }; + + static iterator begin() { return iterator(1); } + static iterator end() { return iterator(num_types+1); } + + bool operator==(const Symbol symbol) { return (_symbol == symbol); } + bool operator!=(const Symbol symbol) { return (_symbol != symbol); } + + bool operator==(const DataType other) { return (_symbol == other._symbol); } + bool operator!=(const DataType other) { return (_symbol != other._symbol); } + private: Symbol _symbol; }; diff --git a/libs/ardour/ardour/destructive_filesource.h b/libs/ardour/ardour/destructive_filesource.h index 5b773898c3..fb2a3be47b 100644 --- a/libs/ardour/ardour/destructive_filesource.h +++ b/libs/ardour/ardour/destructive_filesource.h @@ -49,7 +49,7 @@ class DestructiveFileSource : public SndFileSource { static void setup_standard_crossfades (jack_nframes_t sample_rate); protected: - jack_nframes_t write_unlocked (Sample *src, jack_nframes_t cnt, char * workbuf); + jack_nframes_t write_unlocked (Sample *src, jack_nframes_t cnt); virtual void handle_header_position_change (); @@ -65,7 +65,7 @@ class DestructiveFileSource : public SndFileSource { Sample* xfade_buf; void init (); - jack_nframes_t crossfade (Sample* data, jack_nframes_t cnt, int dir, char * workbuf); + jack_nframes_t crossfade (Sample* data, jack_nframes_t cnt, int dir); void set_timeline_position (jack_nframes_t); }; diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h index ebce516d8b..08dea4fb27 100644 --- a/libs/ardour/ardour/diskstream.h +++ b/libs/ardour/ardour/diskstream.h @@ -69,9 +69,9 @@ class Diskstream : public Stateful, public sigc::trackable ARDOUR::IO* io() const { return _io; } void set_io (ARDOUR::IO& io); - virtual Diskstream& ref() { _refcnt++; return *this; } - void unref() { if (_refcnt) _refcnt--; if (_refcnt == 0) delete this; } - uint32_t refcnt() const { return _refcnt; } + Diskstream& ref() { _refcnt++; return *this; } + void unref() { if (_refcnt) _refcnt--; if (_refcnt == 0) delete this; } + uint32_t refcnt() const { return _refcnt; } virtual float playback_buffer_load() const = 0; virtual float capture_buffer_load() const = 0; @@ -117,8 +117,8 @@ class Diskstream : public Stateful, public sigc::trackable uint32_t n_channels() { return _n_channels; } - static jack_nframes_t disk_io_frames() { return disk_io_chunk_frames; } - static void set_disk_io_chunk_frames (uint32_t n) { disk_io_chunk_frames = n; } + static jack_nframes_t disk_io_frames() { return disk_io_chunk_frames; } + static void set_disk_io_chunk_frames (uint32_t n) { disk_io_chunk_frames = n; } /* Stateful */ virtual XMLNode& get_state(void) = 0; diff --git a/libs/ardour/ardour/insert.h b/libs/ardour/ardour/insert.h index a4c4439942..c81d4e5761 100644 --- a/libs/ardour/ardour/insert.h +++ b/libs/ardour/ardour/insert.h @@ -29,6 +29,7 @@ #include <ardour/ardour.h> #include <ardour/redirect.h> #include <ardour/plugin_state.h> +#include <ardour/types.h> class XMLNode; @@ -39,8 +40,8 @@ namespace MIDI { namespace ARDOUR { class Session; -class Plugin; class Route; +class Plugin; class Insert : public Redirect { @@ -149,6 +150,8 @@ class PluginInsert : public Insert } } + PluginType type (); + string describe_parameter (uint32_t); jack_nframes_t latency(); diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h index b116a58b97..818916f185 100644 --- a/libs/ardour/ardour/io.h +++ b/libs/ardour/ardour/io.h @@ -40,6 +40,7 @@ #include <ardour/curve.h> #include <ardour/types.h> #include <ardour/data_type.h> +#include <ardour/port_set.h> using std::string; using std::vector; @@ -50,9 +51,11 @@ namespace ARDOUR { class Session; class AudioEngine; -class Port; class Connection; class Panner; +class Port; +class AudioPort; +class MidiPort; /** A collection of input and output ports with connections. * @@ -139,23 +142,28 @@ class IO : public Stateful, public ARDOUR::StateManager void set_port_latency (jack_nframes_t); Port *output (uint32_t n) const { - if (n < _noutputs) { - return _outputs[n]; + if (n < _outputs.num_ports()) { + return _outputs.port(n); } else { return 0; } } Port *input (uint32_t n) const { - if (n < _ninputs) { - return _inputs[n]; + if (n < _inputs.num_ports()) { + return _inputs.port(n); } else { return 0; } } - uint32_t n_inputs () const { return _ninputs; } - uint32_t n_outputs () const { return _noutputs; } + AudioPort* audio_input(uint32_t n) const; + AudioPort* audio_output(uint32_t n) const; + MidiPort* midi_input(uint32_t n) const; + MidiPort* midi_output(uint32_t n) const; + + uint32_t n_inputs () const { return _inputs.num_ports(); } + uint32_t n_outputs () const { return _outputs.num_ports(); } sigc::signal<void,IOChange,void*> input_changed; sigc::signal<void,IOChange,void*> output_changed; @@ -195,7 +203,7 @@ class IO : public Stateful, public ARDOUR::StateManager /* Peak metering */ float peak_input_power (uint32_t n) { - if (n < std::max (_ninputs, _noutputs)) { + if (n < std::max (n_inputs(), n_outputs())) { return _visible_peak_power[n]; } else { return minus_infinity(); @@ -269,30 +277,30 @@ public: mutable Glib::Mutex io_lock; protected: - Session& _session; - Panner* _panner; - gain_t _gain; - gain_t _effective_gain; - gain_t _desired_gain; - Glib::Mutex declick_lock; - vector<Port*> _outputs; - vector<Port*> _inputs; - vector<float> _peak_power; - vector<float> _visible_peak_power; - string _name; - Connection* _input_connection; - Connection* _output_connection; - PBD::ID _id; - bool no_panner_reset; - XMLNode* deferred_state; - DataType _default_type; + Session& _session; + Panner* _panner; + gain_t _gain; + gain_t _effective_gain; + gain_t _desired_gain; + Glib::Mutex declick_lock; + PortSet _outputs; + PortSet _inputs; + vector<float> _peak_power; + vector<float> _visible_peak_power; + string _name; + Connection* _input_connection; + Connection* _output_connection; + PBD::ID _id; + bool no_panner_reset; + XMLNode* deferred_state; + DataType _default_type; virtual void set_deferred_state() {} void reset_peak_meters(); void reset_panner (); - virtual uint32_t pans_required() const { return _ninputs; } + virtual uint32_t pans_required() const { return n_inputs(); } static void apply_declick (vector<Sample*>&, uint32_t nbufs, jack_nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity); @@ -339,8 +347,6 @@ public: private: - uint32_t _ninputs; - uint32_t _noutputs; /* are these the best variable names ever, or what? */ diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h index 7877bfaf1c..a048cf4021 100644 --- a/libs/ardour/ardour/midi_diskstream.h +++ b/libs/ardour/ardour/midi_diskstream.h @@ -24,6 +24,7 @@ #include <sigc++/signal.h> #include <cmath> +#include <cassert> #include <string> #include <queue> #include <map> @@ -61,27 +62,20 @@ class MidiDiskstream : public Diskstream MidiDiskstream (Session &, const string& name, Diskstream::Flag f = Recordable); MidiDiskstream (Session &, const XMLNode&); - void set_io (ARDOUR::IO& io); - - MidiDiskstream& ref() { _refcnt++; return *this; } - //void unref() { if (_refcnt) _refcnt--; if (_refcnt == 0) delete this; } - //uint32_t refcnt() const { return _refcnt; } - float playback_buffer_load() const; float capture_buffer_load() const; - - //void set_align_style (AlignStyle); - //void set_persistent_align_style (AlignStyle); + + RawMidi* playback_buffer () { return _current_playback_buffer; } + RawMidi* capture_buffer () { return _current_capture_buffer; } void set_record_enabled (bool yn); - //void set_speed (double); + + MidiPlaylist* midi_playlist () { return dynamic_cast<MidiPlaylist*>(_playlist); } int use_playlist (Playlist *); int use_new_playlist (); int use_copy_playlist (); - Playlist *playlist () { return _playlist; } - /* stateful */ XMLNode& get_state(void); @@ -89,8 +83,6 @@ class MidiDiskstream : public Diskstream void monitor_input (bool); - //void handle_input_change (IOChange, void *src); - protected: friend class Session; @@ -108,12 +100,8 @@ class MidiDiskstream : public Diskstream void reset_write_sources (bool, bool force = false); void non_realtime_input_change (); - uint32_t read_data_count() const { return _read_data_count; } - uint32_t write_data_count() const { return _write_data_count; } - protected: - friend class Auditioner; - int seek (jack_nframes_t which_sample, bool complete_refill = false); + int seek (jack_nframes_t which_sample, bool complete_refill = false); protected: friend class MidiTrack; @@ -126,30 +114,17 @@ class MidiDiskstream : public Diskstream /* use unref() to destroy a diskstream */ ~MidiDiskstream(); - MidiPlaylist* _playlist; - - /*Tthe two central butler operations */ - int do_flush (Session::RunContext context, bool force = false) { return 0; } - int do_refill () { return 0; } + /* The two central butler operations */ + int do_flush (Session::RunContext context, bool force = false); + int do_refill (); - int do_refill_with_alloc() { return 0; } - - int read (RawMidi* buf, RawMidi* mixdown_buffer, char * workbuf, jack_nframes_t& start, jack_nframes_t cnt, bool reversed); - - /* XXX fix this redundancy ... */ + int do_refill_with_alloc(); - //void playlist_changed (Change); - //void playlist_modified (); - void playlist_deleted (Playlist*); + int read (RawMidi* buf, jack_nframes_t& start, jack_nframes_t cnt, bool reversed); void finish_capture (bool rec_monitors_input); void transport_stopped (struct tm&, time_t, bool abort); - struct CaptureInfo { - uint32_t start; - uint32_t frames; - }; - void init (Diskstream::Flag); int use_new_write_source (uint32_t n=0); @@ -158,9 +133,6 @@ class MidiDiskstream : public Diskstream void allocate_temporary_buffers (); - //bool realtime_set_speed (double, bool global_change); - void non_realtime_set_speed (); - int use_pending_capture_data (XMLNode& node); void get_input_sources (); @@ -169,8 +141,21 @@ class MidiDiskstream : public Diskstream void setup_destructive_playlist (); void use_destructive_playlist (); - std::list<Region*> _last_capture_regions; - std::vector<SMFSource*> _capturing_sources; + void engage_record_enable (); + void disengage_record_enable (); + + // FIXME: This is basically a single ChannelInfo.. abstractify that concept? + RingBufferNPT<RawMidi>* _playback_buf; + RingBufferNPT<RawMidi>* _capture_buf; + RawMidi* _current_playback_buffer; + RawMidi* _current_capture_buffer; + RawMidi* _playback_wrap_buffer; + RawMidi* _capture_wrap_buffer; + MidiPort* _source_port; + SMFSource* _write_source; ///< aka capturing source + RingBufferNPT<CaptureTransition>* _capture_transition_buf; + RingBufferNPT<RawMidi>::rw_vector _playback_vector; + RingBufferNPT<RawMidi>::rw_vector _capture_vector; }; }; /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/midi_playlist.h b/libs/ardour/ardour/midi_playlist.h index da3a72a3fd..51cb00822e 100644 --- a/libs/ardour/ardour/midi_playlist.h +++ b/libs/ardour/ardour/midi_playlist.h @@ -55,8 +55,8 @@ public: MidiPlaylist (const MidiPlaylist&, jack_nframes_t start, jack_nframes_t cnt, string name, bool hidden = false); - jack_nframes_t read (unsigned char *dst, unsigned char *mixdown, - char * workbuf, jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n=0); + jack_nframes_t read (RawMidi *dst, RawMidi *mixdown, + jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n=0); int set_state (const XMLNode&); UndoAction get_memento() const; diff --git a/libs/ardour/ardour/midi_port.h b/libs/ardour/ardour/midi_port.h new file mode 100644 index 0000000000..9b1092f300 --- /dev/null +++ b/libs/ardour/ardour/midi_port.h @@ -0,0 +1,72 @@ +/* + Copyright (C) 2002 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. + + $Id: port.h 712 2006-07-28 01:08:57Z drobilla $ +*/ + +#ifndef __ardour_midi_port_h__ +#define __ardour_midi_port_h__ + +#include <sigc++/signal.h> +#include <pbd/failed_constructor.h> +#include <ardour/ardour.h> +#include <jack/jack.h> +#include <jack/midiport.h> +#include <ardour/port.h> +#include <ardour/buffer.h> + +namespace ARDOUR { + +class MidiEngine; + +class MidiPort : public Port { + public: + virtual ~MidiPort(); + + DataType type() const { return DataType(DataType::MIDI); } + + MidiBuffer& get_buffer() { + assert(_nframes_this_cycle > 0); + return *_buffer; + } + + void cycle_start(jack_nframes_t nframes); + void cycle_end(); + + size_t capacity() { return _buffer->capacity(); } + size_t size() { return _buffer->size(); } + + /** Assumes that the port is an output port */ + void silence (jack_nframes_t nframes, jack_nframes_t offset) { + // FIXME: silence starting at offset.. + _buffer->clear(); + } + + protected: + friend class AudioEngine; + + MidiPort (jack_port_t *port); + + /* engine isn't supposed to access below here */ + + MidiBuffer* _buffer; + jack_nframes_t _nframes_this_cycle; +}; + +} // namespace ARDOUR + +#endif /* __ardour_midi_port_h__ */ diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h index ec47a91b95..f68c0ba3ca 100644 --- a/libs/ardour/ardour/midi_region.h +++ b/libs/ardour/ardour/midi_region.h @@ -1,6 +1,5 @@ /* - Copyright (C) 2006 Paul Davis - Written by Dave Robillard, 2006 + Copyright (C) 2000-2006 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 @@ -15,6 +14,8 @@ 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. + + $Id: midiregion.h 733 2006-08-01 17:19:38Z drobilla $ */ #ifndef __ardour_midi_region_h__ @@ -27,6 +28,8 @@ #include <ardour/ardour.h> #include <ardour/region.h> +#include <ardour/gain.h> +#include <ardour/logcurve.h> #include <ardour/export.h> class XMLNode; @@ -39,17 +42,9 @@ class Session; class MidiFilter; class MidiSource; -struct MidiRegionState : public RegionState -{ - MidiRegionState (std::string why); - -}; - class MidiRegion : public Region { public: - typedef vector<MidiSource *> SourceList; - MidiRegion (MidiSource&, jack_nframes_t start, jack_nframes_t length, bool announce = true); MidiRegion (MidiSource&, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true); MidiRegion (SourceList &, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true); @@ -59,83 +54,43 @@ class MidiRegion : public Region MidiRegion (SourceList &, const XMLNode&); ~MidiRegion(); - bool source_equivalent (const Region&) const; - - bool speed_mismatch (float) const; - - void lock_sources (); - void unlock_sources (); - MidiSource& source (uint32_t n=0) const { if (n < sources.size()) return *sources[n]; else return *sources[0]; } - - uint32_t n_channels() { return sources.size(); } - vector<string> master_source_names(); - - bool captured() const { return !(_flags & (Region::Flag (Region::Import|Region::External))); } - - virtual jack_nframes_t read_at (unsigned char *buf, unsigned char *mixdown_buffer, - char * workbuf, jack_nframes_t position, jack_nframes_t cnt, - uint32_t chan_n = 0, - jack_nframes_t read_frames = 0, - jack_nframes_t skip_frames = 0) const; + MidiSource& midi_source (uint32_t n=0) const; - jack_nframes_t master_read_at (unsigned char *buf, unsigned char *mixdown_buffer, - char * workbuf, jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n=0) const; + jack_nframes_t read_at (RawMidi* out, RawMidi* mix, + jack_nframes_t position, + jack_nframes_t cnt, + uint32_t chan_n = 0, + jack_nframes_t read_frames = 0, + jack_nframes_t skip_frames = 0) const; + jack_nframes_t master_read_at (RawMidi* buf, RawMidi* mix, + jack_nframes_t position, + jack_nframes_t cnt, + uint32_t chan_n=0) const; XMLNode& state (bool); - XMLNode& get_state (); int set_state (const XMLNode&); - enum FadeShape { - Linear, - Fast, - Slow, - LogA, - LogB, - - }; - int separate_by_channel (ARDOUR::Session&, vector<MidiRegion*>&) const; - uint32_t read_data_count() const { return _read_data_count; } - - ARDOUR::Playlist* playlist() const { return _playlist; } - UndoAction get_memento() const; - /* export */ - - //int exportme (ARDOUR::Session&, ARDOUR::AudioExportSpecification&); - - Region* get_parent(); - private: friend class Playlist; private: - SourceList sources; - SourceList master_sources; /* used when timefx are applied, so - we can always use the original - source. - */ StateManager::State* state_factory (std::string why) const; Change restore_state (StateManager::State&); - jack_nframes_t _read_at (const SourceList&, unsigned char *buf, unsigned char *mixdown_buffer, - char * workbuf, jack_nframes_t position, jack_nframes_t cnt, - uint32_t chan_n = 0, - jack_nframes_t read_frames = 0, - jack_nframes_t skip_frames = 0) const; - - bool verify_start (jack_nframes_t position); - bool verify_length (jack_nframes_t position); - bool verify_start_mutable (jack_nframes_t& start); - bool verify_start_and_length (jack_nframes_t start, jack_nframes_t length); - - void recompute_at_start() {} - void recompute_at_end() {} + jack_nframes_t _read_at (const SourceList&, RawMidi *buf, + jack_nframes_t position, + jack_nframes_t cnt, + uint32_t chan_n = 0, + jack_nframes_t read_frames = 0, + jack_nframes_t skip_frames = 0) const; - void source_deleted (Source*); + void recompute_at_start (); + void recompute_at_end (); }; } /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/midi_source.h b/libs/ardour/ardour/midi_source.h index 8e4da44082..1c00289003 100644 --- a/libs/ardour/ardour/midi_source.h +++ b/libs/ardour/ardour/midi_source.h @@ -45,23 +45,16 @@ class MidiSource : public Source MidiSource (const XMLNode&); virtual ~MidiSource (); - /* returns the number of items in this `midi_source' */ - - // Applicable to MIDI? With what unit? [DR] - virtual jack_nframes_t length() const { - return _length; - } - - virtual jack_nframes_t read (unsigned char *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const; - virtual jack_nframes_t write (unsigned char *src, jack_nframes_t cnt, char * workbuf); + virtual jack_nframes_t read (RawMidi *dst, jack_nframes_t start, jack_nframes_t cnt) const; + virtual jack_nframes_t write (RawMidi *src, jack_nframes_t cnt); virtual void mark_for_remove() = 0; virtual void mark_streaming_write_completed () {} - void set_captured_for (string str) { _captured_for = str; } string captured_for() const { return _captured_for; } + void set_captured_for (string str) { _captured_for = str; } - uint32_t read_data_count() const { return _read_data_count; } + uint32_t read_data_count() const { return _read_data_count; } uint32_t write_data_count() const { return _write_data_count; } static sigc::signal<void,MidiSource*> MidiSourceCreated; @@ -73,16 +66,13 @@ class MidiSource : public Source int set_state (const XMLNode&); protected: - jack_nframes_t _length; - string _captured_for; - - mutable uint32_t _read_data_count; // modified in read() - mutable uint32_t _write_data_count; // modified in write() - - virtual jack_nframes_t read_unlocked (unsigned char *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const = 0; - virtual jack_nframes_t write_unlocked (unsigned char *dst, jack_nframes_t cnt, char * workbuf) = 0; + virtual jack_nframes_t read_unlocked (RawMidi* dst, jack_nframes_t start, jack_nframes_t cn) const = 0; + virtual jack_nframes_t write_unlocked (RawMidi* dst, jack_nframes_t cnt) = 0; - void update_length (jack_nframes_t pos, jack_nframes_t cnt); + mutable Glib::Mutex _lock; + string _captured_for; + mutable uint32_t _read_data_count; ///< modified in read() + mutable uint32_t _write_data_count; ///< modified in write() private: bool file_changed (string path); diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h index 185e840ec9..4b942c7a21 100644 --- a/libs/ardour/ardour/midi_track.h +++ b/libs/ardour/ardour/midi_track.h @@ -48,6 +48,11 @@ public: int silent_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t offset, bool can_record, bool rec_monitors_input); + void process_output_buffers (vector<Sample*>& bufs, uint32_t nbufs, + jack_nframes_t start_frame, jack_nframes_t end_frame, + jack_nframes_t nframes, jack_nframes_t offset, bool with_redirects, int declick, + bool meter); + void set_record_enable (bool yn, void *src); MidiDiskstream& midi_diskstream() const; @@ -59,7 +64,7 @@ public: void set_latency_delay (jack_nframes_t); - int export_stuff (vector<unsigned char*>& buffers, char * workbuf, uint32_t nbufs, + int export_stuff (vector<unsigned char*>& buffers, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t end_frame); void freeze (InterThreadInfo&); diff --git a/libs/ardour/ardour/plugin.h b/libs/ardour/ardour/plugin.h index 6b11a975ca..e5a81f1ef9 100644 --- a/libs/ardour/ardour/plugin.h +++ b/libs/ardour/ardour/plugin.h @@ -47,27 +47,22 @@ class AudioEngine; class Session; class Plugin; + typedef boost::shared_ptr<Plugin> PluginPtr; class PluginInfo { public: - enum Type { - AudioUnit, - LADSPA, - VST - }; - PluginInfo () { } PluginInfo (const PluginInfo &o) : name(o.name), n_inputs(o.n_inputs), n_outputs(o.n_outputs), unique_id(o.unique_id), path (o.path), index(o.index) {} virtual ~PluginInfo () { } - + string name; string category; uint32_t n_inputs; uint32_t n_outputs; - Type type; + ARDOUR::PluginType type; long unique_id; @@ -187,7 +182,7 @@ class Plugin : public Stateful, public sigc::trackable vector<PortControllable*> controls; }; -PluginPtr find_plugin(ARDOUR::Session&, string name, long unique_id, PluginInfo::Type); +PluginPtr find_plugin(ARDOUR::Session&, string name, long unique_id, ARDOUR::PluginType); } // namespace ARDOUR diff --git a/libs/ardour/ardour/port.h b/libs/ardour/ardour/port.h index 86c99cb7e3..cf36f95b87 100644 --- a/libs/ardour/ardour/port.h +++ b/libs/ardour/ardour/port.h @@ -24,34 +24,32 @@ #include <sigc++/signal.h> #include <pbd/failed_constructor.h> #include <ardour/ardour.h> +#include <ardour/data_type.h> #include <jack/jack.h> namespace ARDOUR { class AudioEngine; +class Buffer; +/** Abstract base for all outside ports (eg Jack ports) + */ class Port : public sigc::trackable { public: virtual ~Port() { free (_port); } - Sample *get_buffer (jack_nframes_t nframes) { - if (_flags & JackPortIsOutput) { - return _buffer; - } else { - return (Sample *) jack_port_get_buffer (_port, nframes); - } - } + virtual DataType type() const = 0; + + virtual void cycle_start(jack_nframes_t nframes) {} + virtual void cycle_end() {} + + virtual Buffer& get_buffer() = 0; + + /** Silence/Empty the port, output ports only */ + virtual void silence (jack_nframes_t nframes, jack_nframes_t offset) = 0; - void reset_buffer () { - if (_flags & JackPortIsOutput) { - _buffer = (Sample *) jack_port_get_buffer (_port, 0); - } else { - _buffer = 0; /* catch illegal attempts to use it */ - } - _silent = false; - } std::string name() { return _name; @@ -71,10 +69,6 @@ class Port : public sigc::trackable { return jack_port_is_mine (client, _port); } - const char* type() const { - return _type.c_str(); - } - int connected () const { return jack_port_connected (_port); } @@ -87,38 +81,6 @@ class Port : public sigc::trackable { return jack_port_get_connections (_port); } - void reset_overs () { - _short_overs = 0; - _long_overs = 0; - _overlen = 0; - } - - void reset_peak_meter () { - _peak = 0; - } - - void reset_meters () { - reset_peak_meter (); - reset_overs (); - } - - void enable_metering() { - _metering++; - } - - void disable_metering () { - if (_metering) { _metering--; } - } - - float peak_db() const { return _peak_db; } - jack_default_audio_sample_t peak() const { return _peak; } - - uint32_t short_overs () const { return _short_overs; } - uint32_t long_overs () const { return _long_overs; } - - static void set_short_over_length (jack_nframes_t); - static void set_long_over_length (jack_nframes_t); - bool receives_input() const { return _flags & JackPortIsInput; } @@ -134,6 +96,14 @@ class Port : public sigc::trackable { bool can_monitor () const { return _flags & JackPortCanMonitor; } + + void enable_metering() { + _metering++; + } + + void disable_metering () { + if (_metering) { _metering--; } + } void ensure_monitor_input (bool yn) { jack_port_request_monitor (_port, yn); @@ -151,60 +121,35 @@ class Port : public sigc::trackable { jack_port_set_latency (_port, nframes); } - sigc::signal<void,bool> MonitorInputChanged; - sigc::signal<void,bool> ClockSyncChanged; - bool is_silent() const { return _silent; } - /** Assumes that the port is an audio output port */ - void silence (jack_nframes_t nframes, jack_nframes_t offset) { - if (!_silent) { - memset (_buffer + offset, 0, sizeof (Sample) * nframes); - if (offset == 0) { - /* XXX this isn't really true, but i am not sure - how to set this correctly. we really just - want to set it true when the entire port - buffer has been overrwritten. - */ - _silent = true; - } - } - } - void mark_silence (bool yn) { _silent = yn; } + + sigc::signal<void,bool> MonitorInputChanged; + sigc::signal<void,bool> ClockSyncChanged; - private: + protected: friend class AudioEngine; Port (jack_port_t *port); - void reset (); - /* engine isn't supposed to below here */ - - Sample *_buffer; - - /* cache these 3 from JACK so that we can - access them for reconnecting. - */ + virtual void reset (); + + /* engine isn't supposed to access below here */ + /* cache these 3 from JACK so we can access them for reconnecting */ JackPortFlags _flags; std::string _type; std::string _name; - bool _last_monitor : 1; - bool _silent : 1; - jack_port_t *_port; - jack_nframes_t _overlen; - jack_default_audio_sample_t _peak; - float _peak_db; - uint32_t _short_overs; - uint32_t _long_overs; - unsigned short _metering; - - static jack_nframes_t _long_over_length; - static jack_nframes_t _short_over_length; + jack_port_t* _port; + + unsigned short _metering; + + bool _last_monitor : 1; + bool _silent : 1; }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/port_set.h b/libs/ardour/ardour/port_set.h new file mode 100644 index 0000000000..f8975325a0 --- /dev/null +++ b/libs/ardour/ardour/port_set.h @@ -0,0 +1,151 @@ +/* + Copyright (C) 2006 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_port_set_h__ +#define __ardour_port_set_h__ + +#include <vector> +#include <ardour/port.h> +#include <ardour/audio_port.h> +#include <ardour/midi_port.h> +#include <ardour/chan_count.h> + +namespace ARDOUR { + + +/** An ordered list of Ports, possibly of various types. + * + * This allows access to all the ports as a list, ignoring type, or accessing + * the nth port of a given type. Note that port(n) and nth_audio_port(n) may + * NOT return the same port. + */ +class PortSet { +public: + PortSet(); + + size_t num_ports() const; + size_t num_ports(DataType type) const { return _ports[type.to_index()].size(); } + + void add_port(Port* port); + + Port* port(size_t index) const; + + Port* nth_port_of_type(DataType type, size_t n) const; + + AudioPort* nth_audio_port(size_t n) const; + + MidiPort* nth_midi_port(size_t n) const; + + bool contains(const Port* port) const; + + /** Remove all ports from the PortSet. Ports are not deregistered with + * the engine, it's the caller's responsibility to not leak here! + */ + void clear() { _ports.clear(); } + + const ChanCount& chan_count() const { return _chan_count; } + + bool empty() const { return (_chan_count.get_total_count() == 0); } + + // ITERATORS + + // obviously these iterators will need to get more clever + // experimental phase, it's the interface that counts right now + + class iterator { + public: + + Port* operator*() { return _list.port(_index); } + iterator& operator++() { ++_index; return *this; } // yes, prefix only + bool operator==(const iterator& other) { return (_index == other._index); } + bool operator!=(const iterator& other) { return (_index != other._index); } + + private: + friend class PortSet; + + iterator(PortSet& list, size_t index) : _list(list), _index(index) {} + + PortSet& _list; + size_t _index; + }; + + iterator begin() { return iterator(*this, 0); } + iterator end() { return iterator(*this, _chan_count.get_total_count()); } + + class const_iterator { + public: + + const Port* operator*() { return _list.port(_index); } + const_iterator& operator++() { ++_index; return *this; } // yes, prefix only + bool operator==(const const_iterator& other) { return (_index == other._index); } + bool operator!=(const const_iterator& other) { return (_index != other._index); } + + private: + friend class PortSet; + + const_iterator(const PortSet& list, size_t index) : _list(list), _index(index) {} + + const PortSet& _list; + size_t _index; + }; + + const_iterator begin() const { return const_iterator(*this, 0); } + const_iterator end() const { return const_iterator(*this, _chan_count.get_total_count()); } + + + + class audio_iterator { + public: + + AudioPort* operator*() { return _list.nth_audio_port(_index); } + audio_iterator& operator++() { ++_index; return *this; } // yes, prefix only + bool operator==(const audio_iterator& other) { return (_index == other._index); } + bool operator!=(const audio_iterator& other) { return (_index != other._index); } + + private: + friend class PortSet; + + audio_iterator(PortSet& list, size_t index) : _list(list), _index(index) {} + + PortSet& _list; + size_t _index; + }; + + audio_iterator audio_begin() { return audio_iterator(*this, 0); } + audio_iterator audio_end() { return audio_iterator(*this, _chan_count.get_count(DataType::AUDIO)); } + + + + +private: + // Prevent copies (undefined) + PortSet(const PortSet& copy); + void operator=(const PortSet& other); + + typedef std::vector<Port*> PortVec; + + // Vector of vectors, indexed by DataType::to_index() + std::vector<PortVec> _ports; + + ChanCount _chan_count; +}; + + +} // namespace ARDOUR + +#endif // __ardour_port_set_h__ diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h index 3773a3b893..c0ff8be607 100644 --- a/libs/ardour/ardour/region.h +++ b/libs/ardour/ardour/region.h @@ -21,6 +21,8 @@ #ifndef __ardour_region_h__ #define __ardour_region_h__ +#include <vector> + #include <pbd/undo.h> #include <ardour/ardour.h> @@ -56,6 +58,8 @@ struct RegionState : public StateManager::State class Region : public Stateful, public StateManager { public: + typedef std::vector<Source *> SourceList; + enum Flag { Muted = 0x1, Opaque = 0x2, @@ -89,11 +93,15 @@ class Region : public Stateful, public StateManager static Change LayerChanged; static Change HiddenChanged; - Region (jack_nframes_t start, jack_nframes_t length, + Region (Source& src, jack_nframes_t start, jack_nframes_t length, + const string& name, layer_t = 0, Flag flags = DefaultFlags); + Region (SourceList& srcs, jack_nframes_t start, jack_nframes_t length, + const string& name, layer_t = 0, Flag flags = DefaultFlags); + Region (const Region&, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t = 0, Flag flags = DefaultFlags); - Region (const Region&, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t = 0, Flag flags = DefaultFlags); Region (const Region&); - Region (const XMLNode&); + Region (SourceList& srcs, const XMLNode&); + Region (Source& src, const XMLNode&); virtual ~Region(); const PBD::ID& id() const { return _id; } @@ -118,13 +126,14 @@ class Region : public Stateful, public StateManager jack_nframes_t first_frame() const { return _position; } jack_nframes_t last_frame() const { return _position + _length - 1; } + Flag flags() const { return _flags; } bool hidden() const { return _flags & Hidden; } bool muted() const { return _flags & Muted; } bool opaque () const { return _flags & Opaque; } bool locked() const { return _flags & Locked; } bool automatic() const { return _flags & Automatic; } bool whole_file() const { return _flags & WholeFile ; } - Flag flags() const { return _flags; } + bool captured() const { return !(_flags & (Region::Flag (Region::Import|Region::External))); } virtual bool should_save_state () const { return !(_flags & DoNotSaveState); }; @@ -143,10 +152,8 @@ class Region : public Stateful, public StateManager bool size_equivalent (const Region&) const; bool overlap_equivalent (const Region&) const; bool region_list_equivalent (const Region&) const; - virtual bool source_equivalent (const Region&) const = 0; + bool source_equivalent (const Region&) const; - virtual bool speed_mismatch (float) const = 0; - /* EDITING OPERATIONS */ void set_length (jack_nframes_t, void *src); @@ -184,8 +191,15 @@ class Region : public Stateful, public StateManager void set_playlist (ARDOUR::Playlist*); - virtual void lock_sources () {} - virtual void unlock_sources () {} + void lock_sources (); + void unlock_sources (); + void source_deleted (Source*); + + Source& source (uint32_t n=0) const { return *_sources[ (n < _sources.size()) ? n : 0 ]; } + uint32_t n_channels() const { return _sources.size(); } + + std::vector<string> master_source_names(); + /* serialization */ @@ -205,7 +219,7 @@ class Region : public Stateful, public StateManager static sigc::signal<void,Region*> CheckNewRegion; - virtual Region* get_parent() = 0; + Region* get_parent(); uint64_t last_layer_op() const { return _last_layer_op; } void set_last_layer_op (uint64_t when); @@ -228,29 +242,32 @@ class Region : public Stateful, public StateManager void maybe_uncopy (); void first_edit (); - virtual bool verify_start (jack_nframes_t) = 0; - virtual bool verify_start_and_length (jack_nframes_t, jack_nframes_t) = 0; - virtual bool verify_start_mutable (jack_nframes_t&_start) = 0; - virtual bool verify_length (jack_nframes_t) = 0; + bool verify_start (jack_nframes_t); + bool verify_start_and_length (jack_nframes_t, jack_nframes_t); + bool verify_start_mutable (jack_nframes_t&_start); + bool verify_length (jack_nframes_t); virtual void recompute_at_start () = 0; virtual void recompute_at_end () = 0; - + + PBD::ID _id; + string _name; + Flag _flags; jack_nframes_t _start; jack_nframes_t _length; jack_nframes_t _position; - Flag _flags; jack_nframes_t _sync_position; layer_t _layer; - string _name; mutable RegionEditState _first_edit; int _frozen; - Glib::Mutex lock; - PBD::ID _id; + mutable uint32_t _read_data_count; ///< modified in read() + Change _pending_changed; + uint64_t _last_layer_op; ///< timestamp + Glib::Mutex _lock; ARDOUR::Playlist* _playlist; - mutable uint32_t _read_data_count; // modified in read() - Change pending_changed; - uint64_t _last_layer_op; // timestamp + SourceList _sources; + /** Used when timefx are applied, so we can always use the original source */ + SourceList _master_sources; }; } /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index d1db818e40..493a5e7bc0 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -304,7 +304,7 @@ class Route : public IO void passthru (jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t nframes, jack_nframes_t offset, int declick, bool meter_inputs); - void process_output_buffers (vector<Sample*>& bufs, uint32_t nbufs, + virtual void process_output_buffers (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t nframes, jack_nframes_t offset, bool with_redirects, int declick, bool meter); diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 6eb025f076..7331cbb5db 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -76,7 +76,9 @@ class AudioSource; class Diskstream; class AudioDiskstream; +class MidiDiskstream; class AudioFileSource; +class MidiSource; class Auditioner; class Insert; class Send; @@ -274,6 +276,7 @@ class Session : public sigc::trackable, public Stateful static string change_audio_path_by_name (string oldpath, string oldname, string newname, bool destructive); static string peak_path_from_audio_path (string); string audio_path_from_name (string, uint32_t nchans, uint32_t chan, bool destructive); + string midi_path_from_name (string); void process (jack_nframes_t nframes); @@ -635,7 +638,7 @@ class Session : public sigc::trackable, public Stateful string new_region_name (string); string path_from_region_name (string name, string identifier); - AudioRegion* find_whole_file_parent (AudioRegion&); + Region* find_whole_file_parent (Region& child); void find_equivalent_playlist_regions (Region&, std::vector<Region*>& result); AudioRegion *XMLRegionFactory (const XMLNode&, bool full); @@ -704,6 +707,8 @@ class Session : public sigc::trackable, public Stateful AudioFileSource *create_audio_source_for_session (ARDOUR::AudioDiskstream&, uint32_t which_channel, bool destructive); + MidiSource *create_midi_source_for_session (ARDOUR::MidiDiskstream&); + Source *source_by_id (const PBD::ID&); /* playlist management */ @@ -745,8 +750,7 @@ class Session : public sigc::trackable, public Stateful /* flattening stuff */ - int write_one_audio_track (AudioTrack&, jack_nframes_t start, jack_nframes_t cnt, bool overwrite, vector<AudioSource*>&, - InterThreadInfo& wot); + int write_one_audio_track (AudioTrack&, jack_nframes_t start, jack_nframes_t cnt, bool overwrite, vector<Source*>&, InterThreadInfo& wot); int freeze (InterThreadInfo&); /* session-wide solo/mute/rec-enable */ @@ -853,6 +857,7 @@ class Session : public sigc::trackable, public Stateful } // these commands are implemented in libs/ardour/session_command.cc + Command *memento_command_factory(XMLNode *n); class GlobalSoloStateCommand : public Command { GlobalRouteBooleanState before, after; @@ -987,8 +992,6 @@ class Session : public sigc::trackable, public Stateful ExportContext }; - char * conversion_buffer(RunContext context) { return _conversion_buffers[context]; } - /* VST support */ static long vst_callback (AEffect* effect, @@ -1072,7 +1075,6 @@ class Session : public sigc::trackable, public Stateful vector<Sample *> _passthru_buffers; vector<Sample *> _silent_buffers; vector<Sample *> _send_buffers; - map<RunContext,char*> _conversion_buffers; jack_nframes_t current_block_size; jack_nframes_t _worst_output_latency; jack_nframes_t _worst_input_latency; diff --git a/libs/ardour/ardour/smf_source.h b/libs/ardour/ardour/smf_source.h index 00f8cb26de..83bc47d7d3 100644 --- a/libs/ardour/ardour/smf_source.h +++ b/libs/ardour/ardour/smf_source.h @@ -41,7 +41,7 @@ class SMFSource : public MidiSource { }; /** Constructor for existing external-to-session files */ - SMFSource (std::string path, Flag flags); + SMFSource (std::string path, Flag flags = Flag(0)); /* Constructor for existing in-session files */ SMFSource (const XMLNode&); @@ -55,8 +55,8 @@ class SMFSource : public MidiSource { void set_allow_remove_if_empty (bool yn); void mark_for_remove(); - virtual int update_header (jack_nframes_t when, struct tm&, time_t) = 0; - virtual int flush_header () = 0; + int update_header (jack_nframes_t when, struct tm&, time_t); + int flush_header (); int move_to_trash (const string trash_dir_name); @@ -76,6 +76,9 @@ class SMFSource : public MidiSource { int init (string idstr, bool must_exist); + jack_nframes_t read_unlocked (RawMidi* dst, jack_nframes_t start, jack_nframes_t cn) const; + jack_nframes_t write_unlocked (RawMidi* dst, jack_nframes_t cnt); + bool find (std::string path, bool must_exist, bool& is_new); bool removable() const; bool writable() const { return _flags & Writable; } diff --git a/libs/ardour/ardour/sndfilesource.h b/libs/ardour/ardour/sndfilesource.h index 4764339451..ab3e61eb29 100644 --- a/libs/ardour/ardour/sndfilesource.h +++ b/libs/ardour/ardour/sndfilesource.h @@ -56,8 +56,8 @@ class SndFileSource : public AudioFileSource { protected: void set_header_timeline_position (); - jack_nframes_t read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const; - jack_nframes_t write_unlocked (Sample *dst, jack_nframes_t cnt, char * workbuf); + jack_nframes_t read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const; + jack_nframes_t write_unlocked (Sample *dst, jack_nframes_t cnt); jack_nframes_t write_float (Sample* data, jack_nframes_t pos, jack_nframes_t cnt); diff --git a/libs/ardour/ardour/source.h b/libs/ardour/ardour/source.h index f57ea79854..dc1e93f8f2 100644 --- a/libs/ardour/ardour/source.h +++ b/libs/ardour/ardour/source.h @@ -46,9 +46,16 @@ class Source : public Stateful, public sigc::trackable uint32_t use_cnt() const { return _use_cnt; } void use (); void release (); + + virtual void mark_for_remove() = 0; time_t timestamp() const { return _timestamp; } void stamp (time_t when) { _timestamp = when; } + + /** @return the number of items in this source */ + jack_nframes_t length() const { return _length; } + + virtual jack_nframes_t natural_position() const { return 0; } XMLNode& get_state (); int set_state (const XMLNode&); @@ -56,9 +63,12 @@ class Source : public Stateful, public sigc::trackable sigc::signal<void,Source *> GoingAway; protected: + void update_length (jack_nframes_t pos, jack_nframes_t cnt); + string _name; uint32_t _use_cnt; time_t _timestamp; + jack_nframes_t _length; private: PBD::ID _id; diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index c30c103d3f..00833f6547 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -29,6 +29,7 @@ #include <inttypes.h> #include <jack/types.h> +#include <jack/midiport.h> #include <control_protocol/smpte.h> #include <pbd/id.h> @@ -49,7 +50,7 @@ namespace ARDOUR { typedef uint32_t layer_t; typedef uint64_t microseconds_t; - typedef unsigned char RawMidi; + typedef jack_midi_event_t RawMidi; enum IOChange { NoChange = 0, @@ -245,7 +246,14 @@ namespace ARDOUR { PeakDatum min; PeakDatum max; }; -} + + enum PluginType { + AudioUnit, + LADSPA, + VST + }; + +} // namespace ARDOUR std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf); std::istream& operator>>(std::istream& o, ARDOUR::HeaderFormat& sf); @@ -256,7 +264,6 @@ session_frame_to_track_frame (jack_nframes_t session_frame, double speed) return (jack_nframes_t)( (double)session_frame * speed ); } - static inline jack_nframes_t track_frame_to_session_frame (jack_nframes_t track_frame, double speed) { diff --git a/libs/ardour/ardour/vst_plugin.h b/libs/ardour/ardour/vst_plugin.h index 5253da7b0a..4fb5b0babb 100644 --- a/libs/ardour/ardour/vst_plugin.h +++ b/libs/ardour/ardour/vst_plugin.h @@ -113,6 +113,8 @@ class VSTPluginInfo : public PluginInfo PluginPtr load (Session& session); }; +typedef boost::shared_ptr<VSTPluginInfo> VSTPluginInfoPtr; + } // namespace ARDOUR #endif /* __ardour_vst_plugin_h__ */ diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index 7d2a2103bb..1b9d7d339d 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -47,6 +47,7 @@ #include <ardour/audioplaylist.h> #include <ardour/cycle_timer.h> #include <ardour/audioregion.h> +#include <ardour/audio_port.h> #include "i18n.h" #include <locale.h> @@ -58,7 +59,6 @@ using namespace PBD; size_t AudioDiskstream::_working_buffers_size = 0; Sample* AudioDiskstream::_mixdown_buffer = 0; gain_t* AudioDiskstream::_gain_buffer = 0; -char* AudioDiskstream::_conversion_buffer = 0; AudioDiskstream::AudioDiskstream (Session &sess, const string &name, Diskstream::Flag flag) : Diskstream(sess, name, flag) @@ -188,7 +188,6 @@ AudioDiskstream::allocate_working_buffers() _working_buffers_size = disk_io_frames(); _mixdown_buffer = new Sample[_working_buffers_size]; _gain_buffer = new gain_t[_working_buffers_size]; - _conversion_buffer = new char[_working_buffers_size * 4]; } void @@ -196,11 +195,9 @@ AudioDiskstream::free_working_buffers() { delete _mixdown_buffer; delete _gain_buffer; - delete _conversion_buffer; _working_buffers_size = 0; _mixdown_buffer = 0; _gain_buffer = 0; - _conversion_buffer = 0; } void @@ -668,7 +665,11 @@ AudioDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes rec_offset */ - memcpy (chan.current_capture_buffer, _io->input(n)->get_buffer (rec_nframes) + offset + rec_offset, sizeof (Sample) * rec_nframes); + AudioPort* const ap = _io->audio_input(n); + assert(ap); + assert(rec_nframes <= ap->get_audio_buffer().capacity()); + + memcpy (chan.current_capture_buffer, ap->get_audio_buffer().data(rec_nframes, offset + rec_offset), sizeof (Sample) * rec_nframes); } else { @@ -679,7 +680,10 @@ AudioDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes goto out; } - Sample* buf = _io->input (n)->get_buffer (nframes) + offset; + AudioPort* const ap = _io->audio_input(n); + assert(ap); + + Sample* buf = ap->get_audio_buffer().data(nframes, offset); jack_nframes_t first = chan.capture_vector.len[0]; memcpy (chan.capture_wrap_buffer, buf, sizeof (Sample) * first); @@ -895,7 +899,6 @@ AudioDiskstream::overwrite_existing_buffers () { Sample* mixdown_buffer; float* gain_buffer; - char * workbuf; int ret = -1; bool reversed = (_visible_speed * _session.transport_speed()) < 0.0f; @@ -906,7 +909,6 @@ AudioDiskstream::overwrite_existing_buffers () mixdown_buffer = new Sample[size]; gain_buffer = new float[size]; - workbuf = new char[size*4]; /* reduce size so that we can fill the buffer correctly. */ size--; @@ -932,8 +934,7 @@ AudioDiskstream::overwrite_existing_buffers () jack_nframes_t to_read = size - overwrite_offset; - if (read ((*chan).playback_buf->buffer() + overwrite_offset, mixdown_buffer, gain_buffer, workbuf, - start, to_read, *chan, n, reversed)) { + if (read ((*chan).playback_buf->buffer() + overwrite_offset, mixdown_buffer, gain_buffer, start, to_read, *chan, n, reversed)) { error << string_compose(_("AudioDiskstream %1: when refilling, cannot read %2 from playlist at frame %3"), _id, size, playback_sample) << endmsg; goto out; @@ -943,7 +944,7 @@ AudioDiskstream::overwrite_existing_buffers () cnt -= to_read; - if (read ((*chan).playback_buf->buffer(), mixdown_buffer, gain_buffer, workbuf, + if (read ((*chan).playback_buf->buffer(), mixdown_buffer, gain_buffer, start, cnt, *chan, n, reversed)) { error << string_compose(_("AudioDiskstream %1: when refilling, cannot read %2 from playlist at frame %3"), _id, size, playback_sample) << endmsg; @@ -958,7 +959,6 @@ AudioDiskstream::overwrite_existing_buffers () pending_overwrite = false; delete [] gain_buffer; delete [] mixdown_buffer; - delete [] workbuf; return ret; } @@ -1022,7 +1022,7 @@ AudioDiskstream::internal_playback_seek (jack_nframes_t distance) } int -AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, char * workbuf, jack_nframes_t& start, jack_nframes_t cnt, +AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, jack_nframes_t& start, jack_nframes_t cnt, ChannelInfo& channel_info, int channel, bool reversed) { jack_nframes_t this_read = 0; @@ -1079,7 +1079,7 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, this_read = min(cnt,this_read); - if (audio_playlist()->read (buf+offset, mixdown_buffer, gain_buffer, workbuf, start, this_read, channel) != this_read) { + if (audio_playlist()->read (buf+offset, mixdown_buffer, gain_buffer, start, this_read, channel) != this_read) { error << string_compose(_("AudioDiskstream %1: cannot read %2 from playlist at frame %3"), _id, this_read, start) << endmsg; return -1; @@ -1117,19 +1117,17 @@ AudioDiskstream::do_refill_with_alloc() { Sample* mix_buf = new Sample[disk_io_chunk_frames]; float* gain_buf = new float[disk_io_chunk_frames]; - char* work_buf = new char[disk_io_chunk_frames * 4]; - int ret = _do_refill(mix_buf, gain_buf, work_buf); + int ret = _do_refill(mix_buf, gain_buf); delete [] mix_buf; delete [] gain_buf; - delete [] work_buf; return ret; } int -AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer, char * workbuf) +AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer) { int32_t ret = 0; jack_nframes_t to_read; @@ -1143,7 +1141,6 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer, char * assert(mixdown_buffer); assert(gain_buffer); - assert(workbuf); channels.front().playback_buf->get_write_vector (&vector); @@ -1284,7 +1281,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer, char * if (to_read) { - if (read (buf1, mixdown_buffer, gain_buffer, workbuf, file_frame_tmp, to_read, chan, chan_n, reversed)) { + if (read (buf1, mixdown_buffer, gain_buffer, file_frame_tmp, to_read, chan, chan_n, reversed)) { ret = -1; goto out; } @@ -1302,7 +1299,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer, char * so read some or all of vector.len[1] as well. */ - if (read (buf2, mixdown_buffer, gain_buffer, workbuf, file_frame_tmp, to_read, chan, chan_n, reversed)) { + if (read (buf2, mixdown_buffer, gain_buffer, file_frame_tmp, to_read, chan, chan_n, reversed)) { ret = -1; goto out; } @@ -1336,8 +1333,6 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer, char * int AudioDiskstream::do_flush (Session::RunContext context, bool force_flush) { - char* workbuf = _session.conversion_buffer(context); - uint32_t to_write; int32_t ret = 0; RingBufferNPT<Sample>::rw_vector vector; @@ -1427,7 +1422,7 @@ AudioDiskstream::do_flush (Session::RunContext context, bool force_flush) } } - if ((!(*chan).write_source) || (*chan).write_source->write (vector.buf[0], to_write, workbuf) != to_write) { + if ((!(*chan).write_source) || (*chan).write_source->write (vector.buf[0], to_write) != to_write) { error << string_compose(_("AudioDiskstream %1: cannot write to disk"), _id) << endmsg; return -1; } @@ -1444,7 +1439,7 @@ AudioDiskstream::do_flush (Session::RunContext context, bool force_flush) to_write = min ((jack_nframes_t)(disk_io_chunk_frames - to_write), (jack_nframes_t) vector.len[1]); - if ((*chan).write_source->write (vector.buf[1], to_write, workbuf) != to_write) { + if ((*chan).write_source->write (vector.buf[1], to_write) != to_write) { error << string_compose(_("AudioDiskstream %1: cannot write to disk"), _id) << endmsg; return -1; } diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc index 93d380679d..328c9b25f5 100644 --- a/libs/ardour/audio_playlist.cc +++ b/libs/ardour/audio_playlist.cc @@ -177,7 +177,7 @@ struct RegionSortByLayer { }; jack_nframes_t -AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, char * workbuf, jack_nframes_t start, +AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, jack_nframes_t start, jack_nframes_t cnt, unsigned chan_n) { jack_nframes_t ret = cnt; @@ -250,12 +250,12 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, ch for (vector<Region*>::iterator i = r.begin(); i != r.end(); ++i) { AudioRegion* const ar = dynamic_cast<AudioRegion*>(*i); assert(ar); - ar->read_at (buf, mixdown_buffer, gain_buffer, workbuf, start, cnt, chan_n, read_frames, skip_frames); + ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames); _read_data_count += ar->read_data_count(); } for (vector<Crossfade*>::iterator i = x.begin(); i != x.end(); ++i) { - (*i)->read_at (buf, mixdown_buffer, gain_buffer, workbuf, start, cnt, chan_n); + (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n); /* don't JACK up _read_data_count, since its the same data as we just read from the regions, and the OS should handle that for us. diff --git a/libs/ardour/audio_port.cc b/libs/ardour/audio_port.cc new file mode 100644 index 0000000000..1eee96a54e --- /dev/null +++ b/libs/ardour/audio_port.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2006 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. +*/ + +#include <cassert> +#include <ardour/audio_port.h> +#include <ardour/data_type.h> + +using namespace ARDOUR; +using namespace std; + +jack_nframes_t AudioPort::_short_over_length = 2; +jack_nframes_t AudioPort::_long_over_length = 10; + +AudioPort::AudioPort(jack_port_t* p) + : Port(p) + , _buffer(0) +{ + DataType dt(_type); + assert(dt == DataType::AUDIO); + + reset(); +} + +void +AudioPort::reset() +{ + Port::reset(); + if (_flags & JackPortIsOutput) { + _buffer.clear(); + _silent = true; + } + + _metering = 0; + reset_meters (); +} + +void +AudioPort::cycle_start (jack_nframes_t nframes) +{ + if (_flags & JackPortIsOutput) { + // FIXME: do nothing, we can cache the value (but capacity needs to be set) + _buffer.set_data((Sample*)jack_port_get_buffer (_port, nframes), nframes); + } else { + _buffer.set_data((Sample*)jack_port_get_buffer (_port, nframes), nframes); + } +} + +void +AudioPort::cycle_end() +{ + // whatever... +} diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc index 78af23e3df..409b0e560f 100644 --- a/libs/ardour/audio_track.cc +++ b/libs/ardour/audio_track.cc @@ -627,7 +627,7 @@ AudioTrack::silent_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jac } int -AudioTrack::export_stuff (vector<Sample*>& buffers, char * workbuf, uint32_t nbufs, jack_nframes_t start, jack_nframes_t nframes) +AudioTrack::export_stuff (vector<Sample*>& buffers, uint32_t nbufs, jack_nframes_t start, jack_nframes_t nframes) { gain_t gain_automation[nframes]; gain_t gain_buffer[nframes]; @@ -645,7 +645,7 @@ AudioTrack::export_stuff (vector<Sample*>& buffers, char * workbuf, uint32_t nbu AudioPlaylist* const apl = dynamic_cast<AudioPlaylist*>(diskstream.playlist()); assert(apl); - if (apl->read (buffers[0], mix_buffer, gain_buffer, workbuf, start, nframes) != nframes) { + if (apl->read (buffers[0], mix_buffer, gain_buffer, start, nframes) != nframes) { return -1; } @@ -655,7 +655,7 @@ AudioTrack::export_stuff (vector<Sample*>& buffers, char * workbuf, uint32_t nbu ++bi; for (; bi != buffers.end(); ++bi, ++n) { if (n < diskstream.n_channels()) { - if (apl->read ((*bi), mix_buffer, gain_buffer, workbuf, start, nframes, n) != nframes) { + if (apl->read ((*bi), mix_buffer, gain_buffer, start, nframes, n) != nframes) { return -1; } b = (*bi); @@ -730,7 +730,7 @@ AudioTrack::export_stuff (vector<Sample*>& buffers, char * workbuf, uint32_t nbu void AudioTrack::bounce (InterThreadInfo& itt) { - vector<AudioSource*> srcs; + vector<Source*> srcs; _session.write_one_audio_track (*this, 0, _session.current_end_frame(), false, srcs, itt); } @@ -738,14 +738,14 @@ AudioTrack::bounce (InterThreadInfo& itt) void AudioTrack::bounce_range (jack_nframes_t start, jack_nframes_t end, InterThreadInfo& itt) { - vector<AudioSource*> srcs; + vector<Source*> srcs; _session.write_one_audio_track (*this, start, end, false, srcs, itt); } void AudioTrack::freeze (InterThreadInfo& itt) { - vector<AudioSource*> srcs; + vector<Source*> srcs; string new_playlist_name; Playlist* new_playlist; string dir; diff --git a/libs/ardour/audio_unit.cc b/libs/ardour/audio_unit.cc index 25c8aeb53b..0a31df40ee 100644 --- a/libs/ardour/audio_unit.cc +++ b/libs/ardour/audio_unit.cc @@ -322,7 +322,7 @@ AUPluginInfo::discover () AUPluginInfoPtr plug(new AUPluginInfo); plug->name = AUPluginInfo::get_name (temp); - plug->type = PluginInfo::AudioUnit; + plug->type = ARDOUR::AudioUnit; plug->n_inputs = 0; plug->n_outputs = 0; plug->category = "AudioUnit"; diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 982a7c5971..49c7902bb9 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -28,6 +28,8 @@ #include <ardour/audioengine.h> #include <ardour/buffer.h> #include <ardour/port.h> +#include <ardour/audio_port.h> +#include <ardour/midi_port.h> #include <ardour/session.h> #include <ardour/cycle_timer.h> #include <ardour/utils.h> @@ -43,9 +45,6 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -jack_nframes_t Port::_short_over_length = 2; -jack_nframes_t Port::_long_over_length = 10; - AudioEngine::AudioEngine (string client_name) { session = 0; @@ -258,6 +257,10 @@ AudioEngine::process_callback (jack_nframes_t nframes) return 0; } + // Prepare ports (ie read data if necessary) + for (Ports::iterator i = ports.begin(); i != ports.end(); ++i) + (*i)->cycle_start(nframes); + session->process (nframes); if (!_running) { @@ -268,6 +271,10 @@ AudioEngine::process_callback (jack_nframes_t nframes) _processed_frames = next_processed_frames; return 0; } + + // Finalize ports (ie write data if necessary) + for (Ports::iterator i = ports.begin(); i != ports.end(); ++i) + (*i)->cycle_end(); if (last_monitor_check + monitor_check_interval < next_processed_frames) { for (Ports::iterator i = ports.begin(); i != ports.end(); ++i) { @@ -405,10 +412,16 @@ AudioEngine::register_input_port (DataType type, const string& portname) if (p) { - Port *newport; - if ((newport = new Port (p)) != 0) { + Port* newport = 0; + + if (type == DataType::AUDIO) + newport = new AudioPort (p); + else if (type == DataType::MIDI) + newport = new MidiPort (p); + + if (newport) ports.insert (ports.begin(), newport); - } + return newport; } else { @@ -432,14 +445,22 @@ AudioEngine::register_output_port (DataType type, const string& portname) } } - jack_port_t *p; - + jack_port_t* p = 0; + if ((p = jack_port_register (_jack, portname.c_str(), - type.to_jack_type(), JackPortIsOutput, 0)) != 0) { - Port *newport = new Port (p); - ports.insert (ports.begin(), newport); - return newport; + type.to_jack_type(), JackPortIsOutput, 0)) != 0) { + Port *newport = NULL; + + if (type == DataType::AUDIO) + newport = new AudioPort (p); + else if (type == DataType::MIDI) + newport = new MidiPort (p); + + if (newport) + ports.insert (ports.begin(), newport); + return newport; + } else { _process_lock.unlock(); @@ -597,6 +618,9 @@ AudioEngine::frames_per_cycle () } } +/** Get a port by name. + * Note this can return NULL, it will NOT create a port if it is not found (any more). + */ Port * AudioEngine::get_port_by_name (const string& portname, bool keep) { @@ -611,25 +635,13 @@ AudioEngine::get_port_by_name (const string& portname, bool keep) } } - /* check to see if we have a Port for this name already */ - for (Ports::iterator i = ports.begin(); i != ports.end(); ++i) { if (portname == (*i)->name()) { return (*i); } } - jack_port_t *p; - - if ((p = jack_port_by_name (_jack, portname.c_str())) != 0) { - Port *newport = new Port (p); - if (keep && newport->is_mine (_jack)) { - ports.insert (newport); - } - return newport; - } else { - return 0; - } + return 0; } const char ** @@ -703,12 +715,14 @@ AudioEngine::n_physical_inputs () const } string -AudioEngine::get_nth_physical (uint32_t n, int flag) +AudioEngine::get_nth_physical (DataType type, uint32_t n, int flag) { const char ** ports; uint32_t i; string ret; + assert(type != DataType::NIL); + if (!_running || !_jack) { if (!_has_run) { fatal << _("get_nth_physical called before engine was started") << endmsg; @@ -718,7 +732,7 @@ AudioEngine::get_nth_physical (uint32_t n, int flag) } } - ports = jack_get_ports (_jack, NULL, NULL, JackPortIsPhysical|flag); + ports = jack_get_ports (_jack, NULL, type.to_jack_type(), JackPortIsPhysical|flag); if (ports == 0) { return ""; @@ -951,7 +965,7 @@ AudioEngine::reconnect_to_jack () short_name = long_name.substr (long_name.find_last_of (':') + 1); - if (((*i)->_port = jack_port_register (_jack, short_name.c_str(), (*i)->type(), (*i)->flags(), 0)) == 0) { + if (((*i)->_port = jack_port_register (_jack, short_name.c_str(), (*i)->type().to_jack_type(), (*i)->flags(), 0)) == 0) { error << string_compose (_("could not reregister %1"), (*i)->name()) << endmsg; break; } else { diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc index 20d1dbfbd6..6b810c04ec 100644 --- a/libs/ardour/audioregion.cc +++ b/libs/ardour/audioregion.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2001 Paul Davis + Copyright (C) 2000-2006 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 @@ -57,25 +57,20 @@ Change AudioRegion::ScaleAmplitudeChanged = ARDOUR::new_change(); Change AudioRegion::EnvelopeChanged = ARDOUR::new_change(); AudioRegionState::AudioRegionState (string why) - : RegionState (why), - _fade_in (0.0, 2.0, 1.0, false), - _fade_out (0.0, 2.0, 1.0, false), - _envelope (0.0, 2.0, 1.0, false) + : RegionState (why) + , _fade_in (0.0, 2.0, 1.0, false) + , _fade_out (0.0, 2.0, 1.0, false) + , _envelope (0.0, 2.0, 1.0, false) { } +/** Basic AudioRegion constructor (one channel) */ AudioRegion::AudioRegion (AudioSource& src, jack_nframes_t start, jack_nframes_t length, bool announce) - : Region (start, length, PBD::basename_nosuffix(src.name()), 0, Region::Flag(Region::DefaultFlags|Region::External)), - _fade_in (0.0, 2.0, 1.0, false), - _fade_out (0.0, 2.0, 1.0, false), - _envelope (0.0, 2.0, 1.0, false) + : Region (src, start, length, PBD::basename_nosuffix(src.name()), 0, Region::Flag(Region::DefaultFlags|Region::External)) + , _fade_in (0.0, 2.0, 1.0, false) + , _fade_out (0.0, 2.0, 1.0, false) + , _envelope (0.0, 2.0, 1.0, false) { - /* basic AudioRegion constructor */ - - sources.push_back (&src); - master_sources.push_back (&src); - src.GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted)); - _scale_amplitude = 1.0; set_default_fades (); @@ -90,18 +85,13 @@ AudioRegion::AudioRegion (AudioSource& src, jack_nframes_t start, jack_nframes_t } } +/* Basic AudioRegion constructor (one channel) */ AudioRegion::AudioRegion (AudioSource& src, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Flag flags, bool announce) - : Region (start, length, name, layer, flags), - _fade_in (0.0, 2.0, 1.0, false), - _fade_out (0.0, 2.0, 1.0, false), - _envelope (0.0, 2.0, 1.0, false) + : Region (src, start, length, name, layer, flags) + , _fade_in (0.0, 2.0, 1.0, false) + , _fade_out (0.0, 2.0, 1.0, false) + , _envelope (0.0, 2.0, 1.0, false) { - /* basic AudioRegion constructor */ - - sources.push_back (&src); - master_sources.push_back (&src); - src.GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted)); - _scale_amplitude = 1.0; set_default_fades (); @@ -115,20 +105,13 @@ AudioRegion::AudioRegion (AudioSource& src, jack_nframes_t start, jack_nframes_t } } +/* Basic AudioRegion constructor (many channels) */ AudioRegion::AudioRegion (SourceList& srcs, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Flag flags, bool announce) - : Region (start, length, name, layer, flags), - _fade_in (0.0, 2.0, 1.0, false), - _fade_out (0.0, 2.0, 1.0, false), - _envelope (0.0, 2.0, 1.0, false) + : Region (srcs, start, length, name, layer, flags) + , _fade_in (0.0, 2.0, 1.0, false) + , _fade_out (0.0, 2.0, 1.0, false) + , _envelope (0.0, 2.0, 1.0, false) { - /* basic AudioRegion constructor */ - - for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) { - sources.push_back (*i); - master_sources.push_back (*i); - (*i)->GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted)); - } - _scale_amplitude = 1.0; set_default_fades (); @@ -143,29 +126,13 @@ AudioRegion::AudioRegion (SourceList& srcs, jack_nframes_t start, jack_nframes_t } +/** Create a new AudioRegion, that is part of an existing one */ AudioRegion::AudioRegion (const AudioRegion& other, jack_nframes_t offset, jack_nframes_t length, const string& name, layer_t layer, Flag flags, bool announce) - : Region (other, offset, length, name, layer, flags), - _fade_in (other._fade_in), - _fade_out (other._fade_out), - _envelope (other._envelope, (double) offset, (double) offset + length) + : Region (other, offset, length, name, layer, flags) + , _fade_in (other._fade_in) + , _fade_out (other._fade_out) + , _envelope (other._envelope, (double) offset, (double) offset + length) { - /* create a new AudioRegion, that is part of an existing one */ - - set<AudioSource*> unique_srcs; - - for (SourceList::const_iterator i= other.sources.begin(); i != other.sources.end(); ++i) { - sources.push_back (*i); - (*i)->GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted)); - unique_srcs.insert (*i); - } - - for (SourceList::const_iterator i = other.master_sources.begin(); i != other.master_sources.end(); ++i) { - if (unique_srcs.find (*i) == unique_srcs.end()) { - (*i)->GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted)); - } - master_sources.push_back (*i); - } - /* return to default fades if the existing ones are too long */ _fade_in_disabled = 0; _fade_out_disabled = 0; @@ -203,28 +170,11 @@ AudioRegion::AudioRegion (const AudioRegion& other, jack_nframes_t offset, jack_ } AudioRegion::AudioRegion (const AudioRegion &other) - : Region (other), - _fade_in (other._fade_in), - _fade_out (other._fade_out), - _envelope (other._envelope) + : Region (other) + , _fade_in (other._fade_in) + , _fade_out (other._fade_out) + , _envelope (other._envelope) { - /* Pure copy constructor */ - - set<AudioSource*> unique_srcs; - - for (SourceList::const_iterator i = other.sources.begin(); i != other.sources.end(); ++i) { - sources.push_back (*i); - (*i)->GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted)); - unique_srcs.insert (*i); - } - - for (SourceList::const_iterator i = other.master_sources.begin(); i != other.master_sources.end(); ++i) { - master_sources.push_back (*i); - if (unique_srcs.find (*i) == unique_srcs.end()) { - (*i)->GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted)); - } - } - _scale_amplitude = other._scale_amplitude; _envelope = other._envelope; @@ -239,15 +189,11 @@ AudioRegion::AudioRegion (const AudioRegion &other) } AudioRegion::AudioRegion (AudioSource& src, const XMLNode& node) - : Region (node), - _fade_in (0.0, 2.0, 1.0, false), - _fade_out (0.0, 2.0, 1.0, false), - _envelope (0.0, 2.0, 1.0, false) + : Region (src, node) + , _fade_in (0.0, 2.0, 1.0, false) + , _fade_out (0.0, 2.0, 1.0, false) + , _envelope (0.0, 2.0, 1.0, false) { - sources.push_back (&src); - master_sources.push_back (&src); - src.GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted)); - set_default_fades (); if (set_state (node)) { @@ -262,26 +208,11 @@ AudioRegion::AudioRegion (AudioSource& src, const XMLNode& node) } AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node) - : Region (node), + : Region (srcs, node), _fade_in (0.0, 2.0, 1.0, false), _fade_out (0.0, 2.0, 1.0, false), _envelope (0.0, 2.0, 1.0, false) { - set<AudioSource*> unique_srcs; - - for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) { - sources.push_back (*i); - (*i)->GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted)); - unique_srcs.insert (*i); - } - - for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) { - master_sources.push_back (*i); - if (unique_srcs.find (*i) == unique_srcs.end()) { - (*i)->GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted)); - } - } - set_default_fades (); _scale_amplitude = 1.0; @@ -383,48 +314,6 @@ AudioRegion::get_memento() const return sigc::bind (mem_fun (*(const_cast<AudioRegion *> (this)), &StateManager::use_state), _current_state_id); } -bool -AudioRegion::verify_length (jack_nframes_t len) -{ - for (uint32_t n=0; n < sources.size(); ++n) { - if (_start > sources[n]->length() - len) { - return false; - } - } - return true; -} - -bool -AudioRegion::verify_start_and_length (jack_nframes_t new_start, jack_nframes_t new_length) -{ - for (uint32_t n=0; n < sources.size(); ++n) { - if (new_length > sources[n]->length() - new_start) { - return false; - } - } - return true; -} -bool -AudioRegion::verify_start (jack_nframes_t pos) -{ - for (uint32_t n=0; n < sources.size(); ++n) { - if (pos > sources[n]->length() - _length) { - return false; - } - } - return true; -} - -bool -AudioRegion::verify_start_mutable (jack_nframes_t& new_start) -{ - for (uint32_t n=0; n < sources.size(); ++n) { - if (new_start > sources[n]->length() - _length) { - new_start = sources[n]->length() - _length; - } - } - return true; -} void AudioRegion::set_envelope_active (bool yn) { @@ -448,11 +337,11 @@ AudioRegion::set_envelope_active (bool yn) jack_nframes_t AudioRegion::read_peaks (PeakData *buf, jack_nframes_t npeaks, jack_nframes_t offset, jack_nframes_t cnt, uint32_t chan_n, double samples_per_unit) const { - if (chan_n >= sources.size()) { + if (chan_n >= _sources.size()) { return 0; } - if (sources[chan_n]->read_peaks (buf, npeaks, offset, cnt, samples_per_unit)) { + if (audio_source(chan_n).read_peaks (buf, npeaks, offset, cnt, samples_per_unit)) { return 0; } else { if (_scale_amplitude != 1.0) { @@ -466,22 +355,22 @@ AudioRegion::read_peaks (PeakData *buf, jack_nframes_t npeaks, jack_nframes_t of } jack_nframes_t -AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, char * workbuf, jack_nframes_t position, +AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n, jack_nframes_t read_frames, jack_nframes_t skip_frames) const { - return _read_at (sources, buf, mixdown_buffer, gain_buffer, workbuf, position, cnt, chan_n, read_frames, skip_frames); + return _read_at (_sources, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, read_frames, skip_frames); } jack_nframes_t -AudioRegion::master_read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, char * workbuf, jack_nframes_t position, +AudioRegion::master_read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n) const { - return _read_at (master_sources, buf, mixdown_buffer, gain_buffer, workbuf, position, cnt, chan_n, 0, 0); + return _read_at (_master_sources, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, 0, 0); } jack_nframes_t -AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buffer, float *gain_buffer, char * workbuf, +AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buffer, float *gain_buffer, jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n, jack_nframes_t read_frames, jack_nframes_t skip_frames) const { @@ -491,7 +380,7 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff /* precondition: caller has verified that we cover the desired section */ - if (chan_n >= sources.size()) { + if (chan_n >= _sources.size()) { return 0; /* read nothing */ } @@ -526,11 +415,12 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff _read_data_count = 0; - if (srcs[chan_n]->read (mixdown_buffer, _start + internal_offset, to_read, workbuf) != to_read) { + AudioSource& src = audio_source(chan_n); + if (src.read (mixdown_buffer, _start + internal_offset, to_read) != to_read) { return 0; /* "read nothing" */ } - _read_data_count += srcs[chan_n]->read_data_count(); + _read_data_count += src.read_data_count(); /* fade in */ @@ -647,13 +537,13 @@ AudioRegion::state (bool full) snprintf (buf, sizeof(buf), "%.12g", _scale_amplitude); node.add_property ("scale-gain", buf); - for (uint32_t n=0; n < sources.size(); ++n) { + for (uint32_t n=0; n < _sources.size(); ++n) { snprintf (buf2, sizeof(buf2), "source-%d", n); - sources[n]->id().print (buf); + _sources[n]->id().print (buf); node.add_property (buf2, buf); } - snprintf (buf, sizeof (buf), "%u", (uint32_t) sources.size()); + snprintf (buf, sizeof (buf), "%u", (uint32_t) _sources.size()); node.add_property ("channels", buf); if (full) { @@ -1058,7 +948,7 @@ AudioRegion::separate_by_channel (Session& session, vector<AudioRegion*>& v) con SourceList srcs; string new_name; - for (SourceList::const_iterator i = master_sources.begin(); i != master_sources.end(); ++i) { + for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) { srcs.clear (); srcs.push_back (*i); @@ -1077,86 +967,6 @@ AudioRegion::separate_by_channel (Session& session, vector<AudioRegion*>& v) con return 0; } -void -AudioRegion::source_deleted (Source* ignored) -{ - delete this; -} - -void -AudioRegion::lock_sources () -{ - SourceList::iterator i; - set<AudioSource*> unique_srcs; - - for (i = sources.begin(); i != sources.end(); ++i) { - unique_srcs.insert (*i); - (*i)->use (); - } - - for (i = master_sources.begin(); i != master_sources.end(); ++i) { - if (unique_srcs.find (*i) == unique_srcs.end()) { - (*i)->use (); - } - } -} - -void -AudioRegion::unlock_sources () -{ - SourceList::iterator i; - set<AudioSource*> unique_srcs; - - for (i = sources.begin(); i != sources.end(); ++i) { - unique_srcs.insert (*i); - (*i)->release (); - } - - for (i = master_sources.begin(); i != master_sources.end(); ++i) { - if (unique_srcs.find (*i) == unique_srcs.end()) { - (*i)->release (); - } - } -} - -vector<string> -AudioRegion::master_source_names () -{ - SourceList::iterator i; - - vector<string> names; - for (i = master_sources.begin(); i != master_sources.end(); ++i) { - names.push_back((*i)->name()); - } - - return names; -} - -bool -AudioRegion::source_equivalent (const Region& o) const -{ - const AudioRegion* other = dynamic_cast<const AudioRegion*>(&o); - if (!other) - return false; - - SourceList::const_iterator i; - SourceList::const_iterator io; - - for (i = sources.begin(), io = other->sources.begin(); i != sources.end() && io != other->sources.end(); ++i, ++io) { - if ((*i)->id() != (*io)->id()) { - return false; - } - } - - for (i = master_sources.begin(), io = other->master_sources.begin(); i != master_sources.end() && io != other->master_sources.end(); ++i, ++io) { - if ((*i)->id() != (*io)->id()) { - return false; - } - } - - return true; -} - int AudioRegion::apply (AudioFilter& filter) { @@ -1170,7 +980,7 @@ AudioRegion::exportme (Session& session, AudioExportSpecification& spec) jack_nframes_t to_read; int status = -1; - spec.channels = sources.size(); + spec.channels = _sources.size(); if (spec.prepare (blocksize, session.frame_rate())) { goto out; @@ -1188,7 +998,7 @@ AudioRegion::exportme (Session& session, AudioExportSpecification& spec) if (spec.channels == 1) { - if (sources.front()->read (spec.dataF, _start + spec.pos, to_read, 0) != to_read) { + if (audio_source().read (spec.dataF, _start + spec.pos, to_read) != to_read) { goto out; } @@ -1198,7 +1008,7 @@ AudioRegion::exportme (Session& session, AudioExportSpecification& spec) for (uint32_t chan = 0; chan < spec.channels; ++chan) { - if (sources[chan]->read (buf, _start + spec.pos, to_read, 0) != to_read) { + if (audio_source(chan).read (buf, _start + spec.pos, to_read) != to_read) { goto out; } @@ -1227,18 +1037,6 @@ AudioRegion::exportme (Session& session, AudioExportSpecification& spec) return status; } -Region* -AudioRegion::get_parent() -{ - Region* r = 0; - - if (_playlist) { - r = _playlist->session().find_whole_file_parent (*this); - } - - return r; -} - void AudioRegion::set_scale_amplitude (gain_t g) { @@ -1260,7 +1058,6 @@ AudioRegion::normalize_to (float target_dB) { const jack_nframes_t blocksize = 64 * 1024; Sample buf[blocksize]; - char workbuf[blocksize * 4]; jack_nframes_t fpos; jack_nframes_t fend; jack_nframes_t to_read; @@ -1289,7 +1086,7 @@ AudioRegion::normalize_to (float target_dB) /* read it in */ - if (source (n).read (buf, fpos, to_read, workbuf) != to_read) { + if (audio_source (n).read (buf, fpos, to_read) != to_read) { return; } @@ -1372,16 +1169,23 @@ AudioRegion::resume_fade_out () bool AudioRegion::speed_mismatch (float sr) const { - if (sources.empty()) { + if (_sources.empty()) { /* impossible, but ... */ return false; } - float fsr = sources.front()->sample_rate(); + float fsr = audio_source().sample_rate(); return fsr != sr; } +AudioSource& +AudioRegion::audio_source (uint32_t n) const +{ + // Guaranteed to succeed (use a static cast?) + return dynamic_cast<AudioSource&>(source(n)); +} + extern "C" { int region_read_peaks_from_c (void *arg, uint32_t npeaks, uint32_t start, uint32_t cnt, intptr_t data, uint32_t n_chan, double samples_per_unit) @@ -1397,7 +1201,7 @@ uint32_t region_length_from_c (void *arg) uint32_t sourcefile_length_from_c (void *arg, double zoom_factor) { - return ( (AudioRegion *) arg)->source().available_peaks (zoom_factor) ; + return ( (AudioRegion *) arg)->audio_source().available_peaks (zoom_factor) ; } } /* extern "C" */ diff --git a/libs/ardour/audiosource.cc b/libs/ardour/audiosource.cc index bf7a32c885..bf97ef848a 100644 --- a/libs/ardour/audiosource.cc +++ b/libs/ardour/audiosource.cc @@ -379,17 +379,17 @@ AudioSource::initialize_peakfile (bool newfile, string audio_path) } jack_nframes_t -AudioSource::read (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const +AudioSource::read (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const { Glib::Mutex::Lock lm (_lock); - return read_unlocked (dst, start, cnt, workbuf); + return read_unlocked (dst, start, cnt); } jack_nframes_t -AudioSource::write (Sample *dst, jack_nframes_t cnt, char * workbuf) +AudioSource::write (Sample *dst, jack_nframes_t cnt) { Glib::Mutex::Lock lm (_lock); - return write_unlocked (dst, cnt, workbuf); + return write_unlocked (dst, cnt); } int @@ -406,7 +406,6 @@ AudioSource::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t int ret = -1; PeakData* staging = 0; Sample* raw_staging = 0; - char * workbuf = 0; int peakfile = -1; expected_peaks = (cnt / (double) frames_per_peak); @@ -445,9 +444,8 @@ AudioSource::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t */ Sample* raw_staging = new Sample[cnt]; - workbuf = new char[cnt*4]; - if (read_unlocked (raw_staging, start, cnt, workbuf) != cnt) { + if (read_unlocked (raw_staging, start, cnt) != cnt) { error << _("cannot read sample data for unscaled peak computation") << endmsg; return -1; } @@ -458,7 +456,6 @@ AudioSource::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t } delete [] raw_staging; - delete [] workbuf; return 0; } @@ -624,7 +621,6 @@ AudioSource::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t jack_nframes_t nvisual_peaks = 0; jack_nframes_t chunksize = (jack_nframes_t) min (cnt, (jack_nframes_t) 4096); raw_staging = new Sample[chunksize]; - workbuf = new char[chunksize *4]; jack_nframes_t frame_pos = start; double pixel_pos = floor (frame_pos / samples_per_visual_peak); @@ -640,7 +636,7 @@ AudioSource::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t to_read = min (chunksize, (_length - current_frame)); - if ((frames_read = read_unlocked (raw_staging, current_frame, to_read, workbuf)) == 0) { + if ((frames_read = read_unlocked (raw_staging, current_frame, to_read)) == 0) { error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3") , _name, to_read, current_frame) << endmsg; @@ -688,10 +684,6 @@ AudioSource::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t delete [] raw_staging; } - if (workbuf) { - delete [] workbuf; - } - return ret; } @@ -760,7 +752,6 @@ AudioSource::do_build_peak (jack_nframes_t first_frame, jack_nframes_t cnt) Sample xmin, xmax; uint32_t peaki; PeakData* peakbuf; - char * workbuf = 0; jack_nframes_t frames_read; jack_nframes_t frames_to_read; off_t first_peak_byte; @@ -781,8 +772,6 @@ AudioSource::do_build_peak (jack_nframes_t first_frame, jack_nframes_t cnt) peakbuf = new PeakData[(cnt/frames_per_peak)+1]; peaki = 0; - workbuf = new char[max(frames_per_peak, cnt) * 4]; - if ((peakfile = ::open (peakpath.c_str(), O_RDWR|O_CREAT, 0664)) < 0) { error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg; return -1; @@ -794,7 +783,7 @@ AudioSource::do_build_peak (jack_nframes_t first_frame, jack_nframes_t cnt) /* lock for every read */ - if ((frames_read = read (buf, current_frame, frames_to_read, workbuf)) != frames_to_read) { + if ((frames_read = read (buf, current_frame, frames_to_read)) != frames_to_read) { error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg; goto out; } @@ -831,8 +820,6 @@ AudioSource::do_build_peak (jack_nframes_t first_frame, jack_nframes_t cnt) if (peakfile >= 0) { close (peakfile); } - if (workbuf) - delete [] workbuf; return ret; } @@ -889,11 +876,3 @@ AudioSource::available_peaks (double zoom_factor) const return (end/sizeof(PeakData)) * frames_per_peak; } -void -AudioSource::update_length (jack_nframes_t pos, jack_nframes_t cnt) -{ - if (pos + cnt > _length) { - _length = pos+cnt; - } -} - diff --git a/libs/ardour/buffer.cc b/libs/ardour/buffer.cc new file mode 100644 index 0000000000..d3791eaed1 --- /dev/null +++ b/libs/ardour/buffer.cc @@ -0,0 +1,107 @@ +/* + Copyright (C) 2006 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. +*/ + +#include <ardour/buffer.h> +#include <iostream> + +namespace ARDOUR { + + +Buffer* +Buffer::create(DataType type, size_t capacity) +{ + if (type == DataType::AUDIO) + return new AudioBuffer(capacity); + else if (type == DataType::MIDI) + return new MidiBuffer(capacity); + else + return NULL; +} + + +AudioBuffer::AudioBuffer(size_t capacity) + : Buffer(DataType::AUDIO, capacity) + , _data(NULL) +{ + _size = capacity; // For audio buffers, size = capacity (always) + if (capacity > 0) { +#ifdef NO_POSIX_MEMALIGN + _data = (Sample *) malloc(sizeof(Sample) * capacity); +#else + posix_memalign((void**)&_data, 16, sizeof(Sample) * capacity); +#endif + assert(_data); + clear(); + _owns_data = true; + } else { + _owns_data = false; + } +} + +AudioBuffer::~AudioBuffer() +{ + if (_owns_data) + free(_data); +} + +// FIXME: mirroring for MIDI buffers? +MidiBuffer::MidiBuffer(size_t capacity) + : Buffer(DataType::MIDI, capacity) + , _owns_data(true) + , _data(NULL) +{ + assert(capacity > 0); + + _size = capacity; // For audio buffers, size = capacity (always) +#ifdef NO_POSIX_MEMALIGN + _data = (RawMidi *) malloc(sizeof(RawMidi) * capacity); +#else + posix_memalign((void**)&_data, 16, sizeof(RawMidi) * capacity); +#endif + assert(_data); + memset(_data, 0, sizeof(RawMidi) * capacity); +} + +MidiBuffer::~MidiBuffer() +{ + if (_owns_data) + free(_data); +} + +/** Note that offset and nframes refer to sample time, not actual buffer locations */ +void +MidiBuffer::write(const Buffer& src, jack_nframes_t offset, jack_nframes_t nframes) +{ + assert(src.type() == DataType::MIDI); + assert(offset == 0); + MidiBuffer& msrc = (MidiBuffer&)src; + _size = 0; + for (size_t i=0; i < msrc.size() && msrc.data()[i].time < nframes; ++i) { + assert(i < _capacity); + _data[i] = msrc.data()[i]; + ++_size; + } + assert(_size == msrc.size()); + + if (_size > 0) + std::cerr << "MidiBuffer wrote " << _size << " events.\n"; +} + + +} // namespace ARDOUR + diff --git a/libs/ardour/configuration.cc b/libs/ardour/configuration.cc index 58da77f933..84c3e3a834 100644 --- a/libs/ardour/configuration.cc +++ b/libs/ardour/configuration.cc @@ -236,7 +236,7 @@ Configuration::set_state (const XMLNode& root) } } - AudioDiskstream::set_disk_io_chunk_frames (minimum_disk_io_bytes.get() / sizeof (Sample)); + Diskstream::set_disk_io_chunk_frames (minimum_disk_io_bytes.get() / sizeof (Sample)); return 0; } diff --git a/libs/ardour/coreaudiosource.cc b/libs/ardour/coreaudiosource.cc index 5e9de225d4..f0fcac14e2 100644 --- a/libs/ardour/coreaudiosource.cc +++ b/libs/ardour/coreaudiosource.cc @@ -153,7 +153,7 @@ CoreAudioSource::~CoreAudioSource () } jack_nframes_t -CoreAudioSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const +CoreAudioSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const { OSStatus err = noErr; diff --git a/libs/ardour/crossfade.cc b/libs/ardour/crossfade.cc index dc4c074844..379c9333b0 100644 --- a/libs/ardour/crossfade.cc +++ b/libs/ardour/crossfade.cc @@ -402,7 +402,7 @@ Crossfade::compute (AudioRegion& a, AudioRegion& b, CrossfadeModel model) jack_nframes_t Crossfade::read_at (Sample *buf, Sample *mixdown_buffer, - float *gain_buffer, char * workbuf, jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n, + float *gain_buffer, jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n, jack_nframes_t read_frames, jack_nframes_t skip_frames) { jack_nframes_t offset; @@ -438,8 +438,8 @@ Crossfade::read_at (Sample *buf, Sample *mixdown_buffer, offset = start - _position; - _out->read_at (crossfade_buffer_out, mixdown_buffer, gain_buffer, workbuf, start, to_write, chan_n, read_frames, skip_frames); - _in->read_at (crossfade_buffer_in, mixdown_buffer, gain_buffer, workbuf, start, to_write, chan_n, read_frames, skip_frames); + _out->read_at (crossfade_buffer_out, mixdown_buffer, gain_buffer, start, to_write, chan_n, read_frames, skip_frames); + _in->read_at (crossfade_buffer_in, mixdown_buffer, gain_buffer, start, to_write, chan_n, read_frames, skip_frames); float* fiv = new float[to_write]; float* fov = new float[to_write]; diff --git a/libs/ardour/destructive_filesource.cc b/libs/ardour/destructive_filesource.cc index 43fafff30a..65ca8dae67 100644 --- a/libs/ardour/destructive_filesource.cc +++ b/libs/ardour/destructive_filesource.cc @@ -158,7 +158,7 @@ DestructiveFileSource::clear_capture_marks () } jack_nframes_t -DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in, char * workbuf) +DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in) { jack_nframes_t xfade = min (xfade_frames, cnt); jack_nframes_t nofade = cnt - xfade; @@ -272,7 +272,7 @@ DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in, } jack_nframes_t -DestructiveFileSource::write_unlocked (Sample* data, jack_nframes_t cnt, char * workbuf) +DestructiveFileSource::write_unlocked (Sample* data, jack_nframes_t cnt) { jack_nframes_t old_file_pos; @@ -297,7 +297,7 @@ DestructiveFileSource::write_unlocked (Sample* data, jack_nframes_t cnt, char * jack_nframes_t ofilepos = file_pos; // fade in - if (crossfade (data, subcnt, 1, workbuf) != subcnt) { + if (crossfade (data, subcnt, 1) != subcnt) { return 0; } @@ -306,7 +306,7 @@ DestructiveFileSource::write_unlocked (Sample* data, jack_nframes_t cnt, char * // fade out subcnt = cnt - subcnt; - if (crossfade (tmpdata, subcnt, 0, workbuf) != subcnt) { + if (crossfade (tmpdata, subcnt, 0) != subcnt) { return 0; } @@ -324,7 +324,7 @@ DestructiveFileSource::write_unlocked (Sample* data, jack_nframes_t cnt, char * /* move to the correct location place */ file_pos = capture_start_frame; - if (crossfade (data, cnt, 1, workbuf) != cnt) { + if (crossfade (data, cnt, 1) != cnt) { return 0; } @@ -337,7 +337,7 @@ DestructiveFileSource::write_unlocked (Sample* data, jack_nframes_t cnt, char * _capture_start = false; _capture_end = false; - if (crossfade (data, cnt, 0, workbuf) != cnt) { + if (crossfade (data, cnt, 0) != cnt) { return 0; } diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc index 9312de5bf1..b2d481077f 100644 --- a/libs/ardour/diskstream.cc +++ b/libs/ardour/diskstream.cc @@ -19,6 +19,7 @@ */ #include <fstream> +#include <cassert> #include <cstdio> #include <unistd.h> #include <cmath> @@ -55,7 +56,12 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -jack_nframes_t Diskstream::disk_io_chunk_frames = 0; +/* XXX This goes uninitialized when there is no ~/.ardour2 directory. + * I can't figure out why, so this will do for now (just stole the + * default from configuration_vars.h). 0 is not a good value for + * allocating buffer sizes.. + */ +jack_nframes_t Diskstream::disk_io_chunk_frames = 1024 * 256; sigc::signal<void,Diskstream*> Diskstream::DiskstreamCreated; sigc::signal<void,list<Source*>*> Diskstream::DeleteSources; diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc index b70a7bbc9c..c68eb16aae 100644 --- a/libs/ardour/import.cc +++ b/libs/ardour/import.cc @@ -57,7 +57,6 @@ Session::import_audiofile (import_status& status) SF_INFO info; float *data = 0; Sample **channel_data = 0; - char * workbuf = 0; long nfiles = 0; long n; string basepath; @@ -156,7 +155,6 @@ Session::import_audiofile (import_status& status) data = new float[BLOCKSIZE * info.channels]; channel_data = new Sample * [ info.channels ]; - workbuf = new char[BLOCKSIZE * 4]; for (n = 0; n < info.channels; ++n) { channel_data[n] = new Sample[BLOCKSIZE]; @@ -188,7 +186,7 @@ Session::import_audiofile (import_status& status) /* flush to disk */ for (chn = 0; chn < info.channels; ++chn) { - newfiles[chn]->write (channel_data[chn], nread, workbuf); + newfiles[chn]->write (channel_data[chn], nread); } so_far += nread; @@ -255,9 +253,6 @@ Session::import_audiofile (import_status& status) if (data) { delete [] data; } - if (workbuf) { - delete [] workbuf; - } if (channel_data) { for (n = 0; n < info.channels; ++n) { diff --git a/libs/ardour/insert.cc b/libs/ardour/insert.cc index a057fef931..02d7bf0bb6 100644 --- a/libs/ardour/insert.cc +++ b/libs/ardour/insert.cc @@ -30,9 +30,18 @@ #include <ardour/port.h> #include <ardour/route.h> #include <ardour/ladspa_plugin.h> + +#ifdef VST_SUPPORT #include <ardour/vst_plugin.h> +#endif + +#ifdef HAVE_COREAUDIO +#include <ardour/audio_unit.h> +#endif + #include <ardour/audioengine.h> #include <ardour/session.h> +#include <ardour/types.h> #include "i18n.h" @@ -45,7 +54,6 @@ Insert::Insert(Session& s, Placement p) { } - Insert::Insert(Session& s, Placement p, int imin, int imax, int omin, int omax) : Redirect (s, s.next_insert_name(), p, imin, imax, omin, omax) { @@ -505,6 +513,9 @@ PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other) #ifdef VST_SUPPORT boost::shared_ptr<VSTPlugin> vp; #endif +#ifdef HAVE_COREAUDIO + boost::shared_ptr<AUPlugin> ap; +#endif if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) { return boost::shared_ptr<Plugin> (new LadspaPlugin (*lp)); @@ -512,6 +523,10 @@ PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other) } else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) { return boost::shared_ptr<Plugin> (new VSTPlugin (*vp)); #endif +#ifdef HAVE_COREAUDIO + } else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) { + return boost::shared_ptr<Plugin> (new AUPlugin (*ap)); +#endif } fatal << string_compose (_("programming error: %1"), @@ -630,7 +645,7 @@ PluginInsert::set_state(const XMLNode& node) XMLPropertyList plist; const XMLProperty *prop; long unique = 0; - PluginInfo::Type type; + ARDOUR::PluginType type; if ((prop = node.property ("type")) == 0) { error << _("XML node describing insert is missing the `type' field") << endmsg; @@ -638,9 +653,9 @@ PluginInsert::set_state(const XMLNode& node) } if (prop->value() == X_("ladspa") || prop->value() == X_("Ladspa")) { /* handle old school sessions */ - type = PluginInfo::LADSPA; + type = ARDOUR::LADSPA; } else if (prop->value() == X_("vst")) { - type = PluginInfo::VST; + type = ARDOUR::VST; } else { error << string_compose (_("unknown plugin type %1 in plugin insert state"), prop->value()) @@ -807,6 +822,35 @@ PluginInsert::state_factory (std::string why) const return state; } +ARDOUR::PluginType +PluginInsert::type () +{ + boost::shared_ptr<LadspaPlugin> lp; +#ifdef VST_SUPPORT + boost::shared_ptr<VSTPlugin> vp; +#endif +#ifdef HAVE_COREAUDIO + boost::shared_ptr<AUPlugin> ap; +#endif + + PluginPtr other = plugin (); + + if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) { + return ARDOUR::LADSPA; +#ifdef VST_SUPPORT + } else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) { + return ARDOUR::VST; +#endif +#ifdef HAVE_COREAUDIO + } else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) { + return ARDOUR::AudioUnit; +#endif + } else { + /* NOT REACHED */ + return (ARDOUR::PluginType) 0; + } +} + /*************************************************************** Port inserts: send output to a port, pick up input at a port ***************************************************************/ @@ -869,10 +913,11 @@ PortInsert::run (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, return; } - uint32_t n; + //uint32_t n; vector<Port*>::iterator o; vector<Port*>::iterator i; +#if 0 /* deliver output */ for (o = _outputs.begin(), n = 0; o != _outputs.end(); ++o, ++n) { @@ -885,6 +930,7 @@ PortInsert::run (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, for (i = _inputs.begin(), n = 0; i != _inputs.end(); ++i, ++n) { memcpy (bufs[min(nbufs,n)], (*i)->get_buffer (nframes) + offset, sizeof (Sample) * nframes); } +#endif } XMLNode& diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index 4d2d26f801..9a41d74cee 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2000-2006 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 @@ -32,6 +32,8 @@ #include <ardour/audioengine.h> #include <ardour/io.h> #include <ardour/port.h> +#include <ardour/audio_port.h> +#include <ardour/midi_port.h> #include <ardour/connection.h> #include <ardour/session.h> #include <ardour/cycle_timer.h> @@ -65,12 +67,12 @@ const string IO::state_node_name = "IO"; bool IO::connecting_legal = false; bool IO::ports_legal = false; bool IO::panners_legal = false; -sigc::signal<void> IO::Meter; -sigc::signal<int> IO::ConnectingLegal; -sigc::signal<int> IO::PortsLegal; -sigc::signal<int> IO::PannersLegal; +sigc::signal<void> IO::Meter; +sigc::signal<int> IO::ConnectingLegal; +sigc::signal<int> IO::PortsLegal; +sigc::signal<int> IO::PannersLegal; sigc::signal<void,uint32_t> IO::MoreOutputs; -sigc::signal<int> IO::PortsCreated; +sigc::signal<int> IO::PortsCreated; Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT; @@ -91,10 +93,12 @@ static double direct_gain_to_control (gain_t gain) { return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0); } +/* static bool sort_ports_by_name (Port* a, Port* b) { return a->name() < b->name(); } +*/ /** @param default_type The type of port that will be created by ensure_io @@ -119,8 +123,6 @@ IO::IO (Session& s, string name, _input_connection = 0; _output_connection = 0; pending_state_node = 0; - _ninputs = 0; - _noutputs = 0; no_panner_reset = false; deferred_state = 0; @@ -144,13 +146,12 @@ IO::~IO () Glib::Mutex::Lock guard (m_meter_signal_lock); Glib::Mutex::Lock lm (io_lock); - vector<Port *>::iterator i; - for (i = _inputs.begin(); i != _inputs.end(); ++i) { + for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { _session.engine().unregister_port (*i); } - for (i = _outputs.begin(); i != _outputs.end(); ++i) { + for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { _session.engine().unregister_port (*i); } @@ -162,7 +163,7 @@ IO::silence (jack_nframes_t nframes, jack_nframes_t offset) { /* io_lock, not taken: function must be called from Session::process() calltree */ - for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { + for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { (*i)->silence (nframes, offset); } } @@ -227,13 +228,13 @@ IO::pan_automated (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t start, /* io_lock, not taken: function must be called from Session::process() calltree */ - if (_noutputs == 0) { + if (n_outputs() == 0) { return; } - if (_noutputs == 1) { + if (n_outputs() == 1) { - dst = output(0)->get_buffer (nframes) + offset; + dst = audio_output(0)->get_audio_buffer().data (nframes, offset); for (uint32_t n = 0; n < nbufs; ++n) { if (bufs[n] != dst) { @@ -246,18 +247,15 @@ IO::pan_automated (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t start, return; } - uint32_t o; - vector<Port *>::iterator out; + uint32_t o = 0; vector<Sample *>::iterator in; Panner::iterator pan; - Sample* obufs[_noutputs]; + Sample* obufs[n_outputs()]; /* the terrible silence ... */ - - for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) { - obufs[o] = (*out)->get_buffer (nframes) + offset; - memset (obufs[o], 0, sizeof (Sample) * nframes); - (*out)->mark_silence (false); + for (PortSet::audio_iterator out = _outputs.audio_begin(); out != _outputs.audio_end(); ++out, ++o) { + (*out)->silence(nframes, offset); + obufs[o] = (*out)->get_audio_buffer().data(nframes, offset); } uint32_t n; @@ -275,7 +273,7 @@ IO::pan (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nfr /* io_lock, not taken: function must be called from Session::process() calltree */ - if (_noutputs == 0) { + if (n_outputs() == 0) { return; } @@ -288,9 +286,9 @@ IO::pan (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nfr return; } - if (_noutputs == 1) { + if (n_outputs() == 1) { - dst = output(0)->get_buffer (nframes) + offset; + dst = audio_output(0)->get_audio_buffer().data(nframes, offset); if (gain_coeff == 0.0f) { @@ -314,7 +312,7 @@ IO::pan (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nfr } } - output(0)->mark_silence (false); + audio_output(0)->mark_silence (false); } else { @@ -336,24 +334,23 @@ IO::pan (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nfr } } - output(0)->mark_silence (false); + audio_output(0)->mark_silence (false); } return; } - uint32_t o; - vector<Port *>::iterator out; + uint32_t o = 0; vector<Sample *>::iterator in; Panner::iterator pan; - Sample* obufs[_noutputs]; + Sample* obufs[n_outputs()]; /* the terrible silence ... */ /* XXX this is wasteful but i see no way to avoid it */ - for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) { - obufs[o] = (*out)->get_buffer (nframes) + offset; + for (PortSet::audio_iterator out = _outputs.audio_begin(); out != _outputs.audio_end(); ++out, ++o) { + obufs[o] = (*out)->get_audio_buffer().data (nframes, offset); memset (obufs[o], 0, sizeof (Sample) * nframes); (*out)->mark_silence (false); } @@ -379,7 +376,7 @@ IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nfram { /* io_lock, not taken: function must be called from Session::process() calltree */ - if (_noutputs == 0) { + if (n_outputs() == 0) { return; } @@ -422,7 +419,7 @@ IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_ { /* io_lock, not taken: function must be called from Session::process() calltree */ - if (_noutputs == 0) { + if (n_outputs() == 0) { return; } @@ -452,14 +449,14 @@ IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_ Sample* src; Sample* dst; uint32_t i; - vector<Port*>::iterator o; vector<Sample*> outs; gain_t actual_gain; if (dg != _gain) { /* unlikely condition */ - for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) { - outs.push_back ((*o)->get_buffer (nframes) + offset); + i = 0; + for (PortSet::audio_iterator o = _outputs.audio_begin(); o != _outputs.audio_end(); ++o, ++i) { + outs.push_back ((*o)->get_audio_buffer().data (nframes, offset)); } } @@ -473,9 +470,10 @@ IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_ actual_gain = _gain; } - for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) { + i = 0; + for (PortSet::audio_iterator o = _outputs.audio_begin(); o != _outputs.audio_end(); ++o, ++i) { - dst = (*o)->get_buffer (nframes) + offset; + dst = (*o)->get_audio_buffer().data(nframes, offset); src = bufs[min(nbufs,i)]; if (dg != _gain || actual_gain == 1.0f) { @@ -506,14 +504,13 @@ IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframe { /* io_lock, not taken: function must be called from Session::process() calltree */ - vector<Port *>::iterator i; - uint32_t n; + uint32_t n = 0; Sample *last = 0; /* we require that bufs.size() >= 1 */ - for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) { - if (i == _inputs.end()) { + for (PortSet::audio_iterator i = _inputs.audio_begin(); n < nbufs; ++i, ++n) { + if (i == _inputs.audio_end()) { break; } @@ -527,7 +524,7 @@ IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframe buffer. */ - last = (*i)->get_buffer (nframes+offset) + offset; + last = (*i)->get_audio_buffer().data(nframes, offset); // the dest buffer's offset has already been applied memcpy (bufs[n], last, sizeof (Sample) * nframes); } @@ -588,7 +585,7 @@ IO::disconnect_input (Port* our_port, string other_port, void* src) /* check that our_port is really one of ours */ - if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) { + if ( ! _inputs.contains(our_port)) { return -1; } @@ -624,7 +621,7 @@ IO::connect_input (Port* our_port, string other_port, void* src) /* check that our_port is really one of ours */ - if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) { + if ( ! _inputs.contains(our_port) ) { return -1; } @@ -656,7 +653,9 @@ IO::disconnect_output (Port* our_port, string other_port, void* src) { Glib::Mutex::Lock lm (io_lock); - if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) { + /* check that our_port is really one of ours */ + + if ( ! _outputs.contains(our_port) ) { return -1; } @@ -691,7 +690,7 @@ IO::connect_output (Port* our_port, string other_port, void* src) /* check that our_port is really one of ours */ - if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) { + if ( ! _outputs.contains(our_port) ) { return -1; } @@ -734,12 +733,14 @@ IO::set_input (Port* other_port, void* src) return -1; } - return connect_input (_inputs.front(), other_port->name(), src); + return connect_input (_inputs.port(0), other_port->name(), src); } int IO::remove_output_port (Port* port, void* src) { + throw; // FIXME +#if 0 IOChange change (NoChange); { @@ -753,7 +754,7 @@ IO::remove_output_port (Port* port, void* src) return -1; } - for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { + for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { if (*i == port) { change = IOChange (change|ConfigurationChanged); if (port->connected()) { @@ -781,7 +782,7 @@ IO::remove_output_port (Port* port, void* src) _session.set_dirty (); return 0; } - +#endif return -1; } @@ -806,7 +807,7 @@ IO::add_output_port (string destination, void* src, DataType type) { Glib::Mutex::Lock lm (io_lock); - if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) { + if (_output_maximum >= 0 && (int) n_outputs() == _output_maximum) { return -1; } @@ -824,15 +825,13 @@ IO::add_output_port (string destination, void* src, DataType type) return -1; } - _outputs.push_back (our_port); - sort (_outputs.begin(), _outputs.end(), sort_ports_by_name); - ++_noutputs; + _outputs.add_port (our_port); drop_output_connection (); setup_peak_meters (); reset_panner (); } - MoreOutputs (_noutputs); /* EMIT SIGNAL */ + MoreOutputs (n_outputs()); /* EMIT SIGNAL */ } if (destination.length()) { @@ -844,12 +843,15 @@ IO::add_output_port (string destination, void* src, DataType type) // pan_changed (src); /* EMIT SIGNAL */ output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */ _session.set_dirty (); + return 0; } int IO::remove_input_port (Port* port, void* src) { + throw; // FIXME +#if 0 IOChange change (NoChange); { @@ -862,7 +864,7 @@ IO::remove_input_port (Port* port, void* src) /* sorry, you can't do this */ return -1; } - for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { + for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { if (*i == port) { change = IOChange (change|ConfigurationChanged); @@ -892,7 +894,7 @@ IO::remove_input_port (Port* port, void* src) _session.set_dirty (); return 0; } - +#endif return -1; } @@ -918,7 +920,7 @@ IO::add_input_port (string source, void* src, DataType type) { Glib::Mutex::Lock lm (io_lock); - if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) { + if (_input_maximum >= 0 && (int) n_inputs() == _input_maximum) { return -1; } @@ -936,15 +938,13 @@ IO::add_input_port (string source, void* src, DataType type) return -1; } - _inputs.push_back (our_port); - sort (_inputs.begin(), _inputs.end(), sort_ports_by_name); - ++_ninputs; + _inputs.add_port(our_port); drop_input_connection (); setup_peak_meters (); reset_panner (); } - MoreOutputs (_ninputs); /* EMIT SIGNAL */ + MoreOutputs (n_inputs()); /* EMIT SIGNAL */ } if (source.length()) { @@ -957,7 +957,7 @@ IO::add_input_port (string source, void* src, DataType type) // pan_changed (src); /* EMIT SIGNAL */ input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */ _session.set_dirty (); - + return 0; } @@ -970,14 +970,16 @@ IO::disconnect_inputs (void* src) { Glib::Mutex::Lock lm (io_lock); - for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { + for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { _session.engine().disconnect (*i); } drop_input_connection (); } } - input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */ + + input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */ + return 0; } @@ -990,7 +992,7 @@ IO::disconnect_outputs (void* src) { Glib::Mutex::Lock lm (io_lock); - for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { + for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { _session.engine().disconnect (*i); } @@ -1000,6 +1002,7 @@ IO::disconnect_outputs (void* src) output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */ _session.set_dirty (); + return 0; } @@ -1008,21 +1011,22 @@ IO::ensure_inputs_locked (uint32_t n, bool clear, void* src) { Port* input_port; bool changed = false; - bool reduced = false; /* remove unused ports */ - while (_ninputs > n) { + while (n_inputs() > n) { + throw; // FIXME + /* _session.engine().unregister_port (_inputs.back()); _inputs.pop_back(); _ninputs--; - reduced = true; changed = true; + */ } /* create any necessary new ports */ - while (_ninputs < n) { + while (n_inputs() < n) { char buf[64]; @@ -1050,9 +1054,7 @@ IO::ensure_inputs_locked (uint32_t n, bool clear, void* src) throw err; } - _inputs.push_back (input_port); - sort (_inputs.begin(), _inputs.end(), sort_ports_by_name); - ++_ninputs; + _inputs.add_port (input_port); changed = true; } @@ -1060,14 +1062,14 @@ IO::ensure_inputs_locked (uint32_t n, bool clear, void* src) drop_input_connection (); setup_peak_meters (); reset_panner (); - MoreOutputs (_ninputs); /* EMIT SIGNAL */ + MoreOutputs (n_inputs()); /* EMIT SIGNAL */ _session.set_dirty (); } if (clear) { /* disconnect all existing ports so that we get a fresh start */ - for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { + for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { _session.engine().disconnect (*i); } } @@ -1080,8 +1082,6 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src) { bool in_changed = false; bool out_changed = false; - bool in_reduced = false; - bool out_reduced = false; bool need_pan_reset; if (_input_maximum >= 0) { @@ -1092,7 +1092,7 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src) nout = min (_output_maximum, (int) nout); } - if (nin == _ninputs && nout == _noutputs && !clear) { + if (nin == n_inputs() && nout == n_outputs() && !clear) { return 0; } @@ -1102,7 +1102,7 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src) Port* port; - if (_noutputs == nout) { + if (n_outputs() == nout) { need_pan_reset = false; } else { need_pan_reset = true; @@ -1110,25 +1110,27 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src) /* remove unused ports */ - while (_ninputs > nin) { + while (n_inputs() > nin) { + throw; // FIXME + /* _session.engine().unregister_port (_inputs.back()); _inputs.pop_back(); _ninputs--; - in_reduced = true; - in_changed = true; + in_changed = true;*/ } - while (_noutputs > nout) { + while (n_outputs() > nout) { + throw; // FIXME + /* _session.engine().unregister_port (_outputs.back()); _outputs.pop_back(); _noutputs--; - out_reduced = true; - out_changed = true; + out_changed = true;*/ } /* create any necessary new ports (of the default type) */ - while (_ninputs < nin) { + while (n_inputs() < nin) { char buf[64]; @@ -1155,14 +1157,13 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src) throw err; } - _inputs.push_back (port); - ++_ninputs; + _inputs.add_port (port); in_changed = true; } /* create any necessary new ports */ - while (_noutputs < nout) { + while (n_outputs() < nout) { char buf[64]; @@ -1188,8 +1189,7 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src) throw err; } - _outputs.push_back (port); - ++_noutputs; + _outputs.add_port (port); out_changed = true; } @@ -1197,11 +1197,11 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src) /* disconnect all existing ports so that we get a fresh start */ - for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { + for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { _session.engine().disconnect (*i); } - for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { + for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { _session.engine().disconnect (*i); } } @@ -1213,19 +1213,17 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src) } if (out_changed) { - sort (_outputs.begin(), _outputs.end(), sort_ports_by_name); drop_output_connection (); output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */ } if (in_changed) { - sort (_inputs.begin(), _inputs.end(), sort_ports_by_name); drop_input_connection (); input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */ } if (in_changed || out_changed) { - MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */ + MoreOutputs (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */ _session.set_dirty (); } @@ -1240,7 +1238,7 @@ IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src) if (_input_maximum >= 0) { n = min (_input_maximum, (int) n); - if (n == _ninputs && !clear) { + if (n == n_inputs() && !clear) { return 0; } } @@ -1257,7 +1255,6 @@ IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src) input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */ _session.set_dirty (); } - return 0; } @@ -1266,10 +1263,9 @@ IO::ensure_outputs_locked (uint32_t n, bool clear, void* src) { Port* output_port; bool changed = false; - bool reduced = false; bool need_pan_reset; - if (_noutputs == n) { + if (n_outputs() == n) { need_pan_reset = false; } else { need_pan_reset = true; @@ -1277,18 +1273,19 @@ IO::ensure_outputs_locked (uint32_t n, bool clear, void* src) /* remove unused ports */ - while (_noutputs > n) { - + while (n_outputs() > n) { + throw; // FIXME + /* _session.engine().unregister_port (_outputs.back()); _outputs.pop_back(); _noutputs--; - reduced = true; changed = true; + */ } /* create any necessary new ports */ - while (_noutputs < n) { + while (n_outputs() < n) { char buf[64]; @@ -1305,9 +1302,7 @@ IO::ensure_outputs_locked (uint32_t n, bool clear, void* src) return -1; } - _outputs.push_back (output_port); - sort (_outputs.begin(), _outputs.end(), sort_ports_by_name); - ++_noutputs; + _outputs.add_port (output_port); changed = true; setup_peak_meters (); @@ -1318,14 +1313,14 @@ IO::ensure_outputs_locked (uint32_t n, bool clear, void* src) if (changed) { drop_output_connection (); - MoreOutputs (_noutputs); /* EMIT SIGNAL */ + MoreOutputs (n_outputs()); /* EMIT SIGNAL */ _session.set_dirty (); } if (clear) { /* disconnect all existing ports so that we get a fresh start */ - for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { + for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { _session.engine().disconnect (*i); } } @@ -1340,7 +1335,7 @@ IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src) if (_output_maximum >= 0) { n = min (_output_maximum, (int) n); - if (n == _noutputs && !clear) { + if (n == n_outputs() && !clear) { return 0; } } @@ -1358,7 +1353,6 @@ IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src) if (changed) { output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */ } - return 0; } @@ -1377,7 +1371,7 @@ IO::reset_panner () { if (panners_legal) { if (!no_panner_reset) { - _panner->reset (_noutputs, pans_required()); + _panner->reset (n_outputs(), pans_required()); } } else { panner_legal_c.disconnect (); @@ -1388,7 +1382,7 @@ IO::reset_panner () int IO::panners_became_legal () { - _panner->reset (_noutputs, pans_required()); + _panner->reset (n_outputs(), pans_required()); _panner->load (); // automation panner_legal_c.disconnect (); return 0; @@ -1442,7 +1436,7 @@ IO::state (bool full_state) } if (need_ins) { - for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { + for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { const char **connections = (*i)->get_connections(); @@ -1479,7 +1473,7 @@ IO::state (bool full_state) if (need_outs) { str = ""; - for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { + for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { const char **connections = (*i)->get_connections(); @@ -1957,13 +1951,13 @@ IO::set_name (string name, void* src) return 0; } - for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { + for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { string current_name = (*i)->short_name(); current_name.replace (current_name.find (_name), _name.length(), name); (*i)->set_name (current_name); } - for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { + for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { string current_name = (*i)->short_name(); current_name.replace (current_name.find (_name), _name.length(), name); (*i)->set_name (current_name); @@ -2004,7 +1998,7 @@ IO::set_port_latency (jack_nframes_t nframes) { Glib::Mutex::Lock lm (io_lock); - for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { + for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { (*i)->set_latency (nframes); } } @@ -2019,7 +2013,7 @@ IO::output_latency () const /* io lock not taken - must be protected by other means */ - for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) { + for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) { if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) { max_latency = latency; } @@ -2038,7 +2032,7 @@ IO::input_latency () const /* io lock not taken - must be protected by other means */ - for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) { + for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) { if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) { max_latency = latency; } @@ -2073,13 +2067,13 @@ IO::use_input_connection (Connection& c, void* src) for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) { - if (!_inputs[n]->connected_to ((*i))) { + if (!_inputs.port(n)->connected_to ((*i))) { /* clear any existing connections */ - _session.engine().disconnect (_inputs[n]); + _session.engine().disconnect (_inputs.port(n)); - } else if (_inputs[n]->connected() > 1) { + } else if (_inputs.port(n)->connected() > 1) { /* OK, it is connected to the port we want, but its also connected to other ports. @@ -2090,7 +2084,7 @@ IO::use_input_connection (Connection& c, void* src) the one we want. */ - _session.engine().disconnect (_inputs[n]); + _session.engine().disconnect (_inputs.port(n)); } } @@ -2103,9 +2097,9 @@ IO::use_input_connection (Connection& c, void* src) for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) { - if (!_inputs[n]->connected_to ((*i))) { + if (!_inputs.port(n)->connected_to ((*i))) { - if (_session.engine().connect (*i, _inputs[n]->name())) { + if (_session.engine().connect (*i, _inputs.port(n)->name())) { return -1; } } @@ -2152,13 +2146,13 @@ IO::use_output_connection (Connection& c, void* src) for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) { - if (!_outputs[n]->connected_to ((*i))) { + if (!_outputs.port(n)->connected_to ((*i))) { /* clear any existing connections */ - _session.engine().disconnect (_outputs[n]); + _session.engine().disconnect (_outputs.port(n)); - } else if (_outputs[n]->connected() > 1) { + } else if (_outputs.port(n)->connected() > 1) { /* OK, it is connected to the port we want, but its also connected to other ports. @@ -2169,7 +2163,7 @@ IO::use_output_connection (Connection& c, void* src) the one we want. */ - _session.engine().disconnect (_outputs[n]); + _session.engine().disconnect (_outputs.port(n)); } } } @@ -2182,9 +2176,9 @@ IO::use_output_connection (Connection& c, void* src) for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) { - if (!_outputs[n]->connected_to ((*i))) { + if (!_outputs.port(n)->connected_to ((*i))) { - if (_session.engine().connect (_outputs[n]->name(), *i)) { + if (_session.engine().connect (_outputs.port(n)->name(), *i)) { return -1; } } @@ -2285,7 +2279,7 @@ IO::GainControllable::get_value (void) const void IO::reset_peak_meters () { - uint32_t limit = max (_ninputs, _noutputs); + uint32_t limit = max (n_inputs(), n_outputs()); for (uint32_t i = 0; i < limit; ++i) { _peak_power[i] = 0; @@ -2295,7 +2289,7 @@ IO::reset_peak_meters () void IO::setup_peak_meters () { - uint32_t limit = max (_ninputs, _noutputs); + uint32_t limit = max (n_inputs(), n_outputs()); while (_peak_power.size() < limit) { _peak_power.push_back (0); @@ -2342,7 +2336,7 @@ void IO::meter () { Glib::Mutex::Lock lm (io_lock); // READER: meter thread. - uint32_t limit = max (_ninputs, _noutputs); + uint32_t limit = max (n_inputs(), n_outputs()); for (uint32_t n = 0; n < limit; ++n) { @@ -2648,11 +2642,11 @@ IO::find_input_port_hole () for (n = 1; n < UINT_MAX; ++n) { char buf[jack_port_name_size()]; - vector<Port*>::iterator i; + PortSet::iterator i = _inputs.begin(); snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n); - for (i = _inputs.begin(); i != _inputs.end(); ++i) { + for ( ; i != _inputs.end(); ++i) { if ((*i)->short_name() == buf) { break; } @@ -2678,11 +2672,11 @@ IO::find_output_port_hole () for (n = 1; n < UINT_MAX; ++n) { char buf[jack_port_name_size()]; - vector<Port*>::iterator i; + PortSet::iterator i = _outputs.begin(); snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n); - for (i = _outputs.begin(); i != _outputs.end(); ++i) { + for ( ; i != _outputs.end(); ++i) { if ((*i)->short_name() == buf) { break; } @@ -2695,3 +2689,28 @@ IO::find_output_port_hole () return n; } + +AudioPort* +IO::audio_input(uint32_t n) const +{ + return dynamic_cast<AudioPort*>(input(n)); +} + +AudioPort* +IO::audio_output(uint32_t n) const +{ + return dynamic_cast<AudioPort*>(output(n)); +} + +MidiPort* +IO::midi_input(uint32_t n) const +{ + return dynamic_cast<MidiPort*>(input(n)); +} + +MidiPort* +IO::midi_output(uint32_t n) const +{ + return dynamic_cast<MidiPort*>(output(n)); +} + diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index a43e5e9024..8722c65a5f 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -47,6 +47,7 @@ #include <ardour/midi_playlist.h> #include <ardour/cycle_timer.h> #include <ardour/midi_region.h> +#include <ardour/midi_port.h> #include "i18n.h" #include <locale.h> @@ -57,7 +58,15 @@ using namespace PBD; MidiDiskstream::MidiDiskstream (Session &sess, const string &name, Diskstream::Flag flag) : Diskstream(sess, name, flag) - , _playlist(NULL) + , _playback_buf(0) + , _capture_buf(0) + , _current_playback_buffer(0) + , _current_capture_buffer(0) + , _playback_wrap_buffer(0) + , _capture_wrap_buffer(0) + , _source_port(0) + , _write_source(0) + , _capture_transition_buf(0) { /* prevent any write sources from being created */ @@ -73,7 +82,15 @@ MidiDiskstream::MidiDiskstream (Session &sess, const string &name, Diskstream::F MidiDiskstream::MidiDiskstream (Session& sess, const XMLNode& node) : Diskstream(sess, node) - , _playlist(NULL) + , _playback_buf(0) + , _capture_buf(0) + , _current_playback_buffer(0) + , _current_capture_buffer(0) + , _playback_wrap_buffer(0) + , _capture_wrap_buffer(0) + , _source_port(0) + , _write_source(0) + , _capture_transition_buf(0) { in_set_state = true; init (Recordable); @@ -105,42 +122,105 @@ MidiDiskstream::init (Diskstream::Flag f) set_block_size (_session.get_block_size()); allocate_temporary_buffers (); - /* FIXME: this is now done before the above. OK? */ - /*pending_overwrite = false; - overwrite_frame = 0; - overwrite_queued = false; - input_change_pending = NoChange;*/ - + _playback_wrap_buffer = new RawMidi[wrap_buffer_size]; + _capture_wrap_buffer = new RawMidi[wrap_buffer_size]; + _playback_buf = new RingBufferNPT<RawMidi> (_session.diskstream_buffer_size()); + _capture_buf = new RingBufferNPT<RawMidi> (_session.diskstream_buffer_size()); + _capture_transition_buf = new RingBufferNPT<CaptureTransition> (128); + _n_channels = 1; } MidiDiskstream::~MidiDiskstream () { Glib::Mutex::Lock lm (state_lock); - - if (_playlist) - _playlist->unref (); } -/* -void -MidiDiskstream::handle_input_change (IOChange change, void *src) -{ - Glib::Mutex::Lock lm (state_lock); - if (!(input_change_pending & change)) { - input_change_pending = IOChange (input_change_pending|change); - _session.request_input_change_handling (); - } -} -*/ void MidiDiskstream::non_realtime_input_change () { + { + Glib::Mutex::Lock lm (state_lock); + + if (input_change_pending == NoChange) { + return; + } + + if (input_change_pending & ConfigurationChanged) { + + assert(_io->n_inputs() == _n_channels); + } + + get_input_sources (); + set_capture_offset (); + + if (first_input_change) { + set_align_style (_persistent_alignment_style); + first_input_change = false; + } else { + set_align_style_from_io (); + } + + input_change_pending = NoChange; + } + + /* reset capture files */ + + reset_write_sources (false); + + /* now refill channel buffers */ + + if (speed() != 1.0f || speed() != -1.0f) { + seek ((jack_nframes_t) (_session.transport_frame() * (double) speed())); + } + else { + seek (_session.transport_frame()); + } } void MidiDiskstream::get_input_sources () { +#if 0 + if (_io->n_inputs() == 0) { + cerr << "MidiDiskstream NO INPUTS?\n"; + return; + } else { + cerr << "INPUTS!\n"; + } + + // FIXME this is weird and really different from AudioDiskstream + + assert(_io->n_inputs() == 1); + assert(_io->midi_input(0)); + _source_port = _io->midi_input(0); + + const char **connections = _io->input(0)->get_connections (); + + if (connections == 0 || connections[0] == 0) { + + if (_source_port) { + // _source_port->disable_metering (); + } + + _source_port = 0; + + } else { + _source_port = dynamic_cast<MidiPort*>( + _session.engine().get_port_by_name (connections[0])); + assert(_source_port); + } + + if (_source_port) { + cerr << "SOURCE PORT!\n"; + } else { + cerr << "NO SOURCE PORT?!\n"; + } + + if (connections) { + free (connections); + } +#endif } int @@ -167,42 +247,7 @@ MidiDiskstream::use_playlist (Playlist* playlist) { assert(dynamic_cast<MidiPlaylist*>(playlist)); - { - Glib::Mutex::Lock lm (state_lock); - - if (playlist == _playlist) { - return 0; - } - - plstate_connection.disconnect(); - plmod_connection.disconnect (); - plgone_connection.disconnect (); - - if (_playlist) { - _playlist->unref(); - } - - _playlist = dynamic_cast<MidiPlaylist*>(playlist); - _playlist->ref(); - - if (!in_set_state && recordable()) { - reset_write_sources (false); - } - - plstate_connection = _playlist->StateChanged.connect (mem_fun (*this, &MidiDiskstream::playlist_changed)); - plmod_connection = _playlist->Modified.connect (mem_fun (*this, &MidiDiskstream::playlist_modified)); - plgone_connection = _playlist->GoingAway.connect (mem_fun (*this, &MidiDiskstream::playlist_deleted)); - } - - if (!overwrite_queued) { - _session.request_overwrite_buffer (this); - overwrite_queued = true; - } - - PlaylistChanged (); /* EMIT SIGNAL */ - _session.set_dirty (); - - return 0; + return Diskstream::use_playlist(playlist); } int @@ -246,7 +291,7 @@ MidiDiskstream::use_copy_playlist () newname = Playlist::bump_name (_playlist->name(), _session); - if ((playlist = new MidiPlaylist (*_playlist, newname)) != 0) { + if ((playlist = new MidiPlaylist (*midi_playlist(), newname)) != 0) { playlist->set_orig_diskstream_id (id()); return use_playlist (playlist); } else { @@ -254,26 +299,18 @@ MidiDiskstream::use_copy_playlist () } } - -void -MidiDiskstream::playlist_deleted (Playlist* pl) -{ - /* this catches an ordering issue with session destruction. playlists - are destroyed before diskstreams. we have to invalidate any handles - we have to the playlist. - */ - - _playlist = 0; -} - - void MidiDiskstream::setup_destructive_playlist () { + Region::SourceList srcs; + + srcs.push_back (_write_source); /* a single full-sized region */ - //MidiRegion* region = new MidiRegion (srcs, 0, max_frames, _name); - //_playlist->add_region (*region, 0); + cerr << "Setup MIDI DS using " << srcs.front()->natural_position () << endl; + + MidiRegion* region = new MidiRegion (srcs, 0, max_frames, _name); + _playlist->add_region (*region, srcs.front()->natural_position()); } void @@ -296,48 +333,431 @@ MidiDiskstream::use_destructive_playlist () delete rl; + assert(region->n_channels() == 1); + _write_source = dynamic_cast<SMFSource*>(®ion->source (0)); + assert(_write_source); + _write_source->set_allow_remove_if_empty (false); + /* the source list will never be reset for a destructive track */ } void -MidiDiskstream::set_io (IO& io) +MidiDiskstream::check_record_status (jack_nframes_t transport_frame, jack_nframes_t nframes, bool can_record) { - _io = &io; - set_align_style_from_io (); -} + // FIXME: waaay too much code to duplicate (AudioDiskstream) + + int possibly_recording; + int rolling; + int change; + const int transport_rolling = 0x4; + const int track_rec_enabled = 0x2; + const int global_rec_enabled = 0x1; + + /* merge together the 3 factors that affect record status, and compute + what has changed. + */ -void -MidiDiskstream::non_realtime_set_speed () -{ - if (_buffer_reallocation_required) - { - Glib::Mutex::Lock lm (state_lock); - allocate_temporary_buffers (); + rolling = _session.transport_speed() != 0.0f; + possibly_recording = (rolling << 2) | (record_enabled() << 1) | can_record; + change = possibly_recording ^ last_possibly_recording; - _buffer_reallocation_required = false; + if (possibly_recording == last_possibly_recording) { + return; } - if (_seek_required) { - if (speed() != 1.0f || speed() != -1.0f) { - seek ((jack_nframes_t) (_session.transport_frame() * (double) speed()), true); + /* change state */ + + /* if per-track or global rec-enable turned on while the other was already on, we've started recording */ + + if ((change & track_rec_enabled) && record_enabled() && (!(change & global_rec_enabled) && can_record) || + ((change & global_rec_enabled) && can_record && (!(change & track_rec_enabled) && record_enabled()))) { + + /* starting to record: compute first+last frames */ + + first_recordable_frame = transport_frame + _capture_offset; + last_recordable_frame = max_frames; + capture_start_frame = transport_frame; + + if (!(last_possibly_recording & transport_rolling) && (possibly_recording & transport_rolling)) { + + /* was stopped, now rolling (and recording) */ + + if (_alignment_style == ExistingMaterial) { + first_recordable_frame += _session.worst_output_latency(); + } else { + first_recordable_frame += _roll_delay; + } + + } else { + + /* was rolling, but record state changed */ + + if (_alignment_style == ExistingMaterial) { + + + if (!_session.get_punch_in()) { + + /* manual punch in happens at the correct transport frame + because the user hit a button. but to get alignment correct + we have to back up the position of the new region to the + appropriate spot given the roll delay. + */ + + capture_start_frame -= _roll_delay; + + /* XXX paul notes (august 2005): i don't know why + this is needed. + */ + + first_recordable_frame += _capture_offset; + + } else { + + /* autopunch toggles recording at the precise + transport frame, and then the DS waits + to start recording for a time that depends + on the output latency. + */ + + first_recordable_frame += _session.worst_output_latency(); + } + + } else { + + if (_session.get_punch_in()) { + first_recordable_frame += _roll_delay; + } else { + capture_start_frame -= _roll_delay; + } + } + } - else { - seek (_session.transport_frame(), true); + + if (_flags & Recordable) { + RingBufferNPT<CaptureTransition>::rw_vector transvec; + _capture_transition_buf->get_write_vector(&transvec); + + if (transvec.len[0] > 0) { + transvec.buf[0]->type = CaptureStart; + transvec.buf[0]->capture_val = capture_start_frame; + _capture_transition_buf->increment_write_ptr(1); + } else { + // bad! + fatal << X_("programming error: capture_transition_buf is full on rec start! inconceivable!") + << endmsg; + } } - _seek_required = false; + } else if (!record_enabled() || !can_record) { + + /* stop recording */ + + last_recordable_frame = transport_frame + _capture_offset; + + if (_alignment_style == ExistingMaterial) { + last_recordable_frame += _session.worst_output_latency(); + } else { + last_recordable_frame += _roll_delay; + } } -} -void -MidiDiskstream::check_record_status (jack_nframes_t transport_frame, jack_nframes_t nframes, bool can_record) -{ + last_possibly_recording = possibly_recording; } int MidiDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes, jack_nframes_t offset, bool can_record, bool rec_monitors_input) { - return 0; + // FIXME: waay too much code to duplicate (AudioDiskstream::process) + int ret = -1; + jack_nframes_t rec_offset = 0; + jack_nframes_t rec_nframes = 0; + bool nominally_recording; + bool re = record_enabled (); + bool collect_playback = false; + + _current_capture_buffer = 0; + _current_playback_buffer = 0; + + /* if we've already processed the frames corresponding to this call, + just return. this allows multiple routes that are taking input + from this diskstream to call our ::process() method, but have + this stuff only happen once. more commonly, it allows both + the AudioTrack that is using this AudioDiskstream *and* the Session + to call process() without problems. + */ + + if (_processed) { + return 0; + } + + check_record_status (transport_frame, nframes, can_record); + + nominally_recording = (can_record && re); + + if (nframes == 0) { + _processed = true; + return 0; + } + + /* This lock is held until the end of AudioDiskstream::commit, so these two functions + must always be called as a pair. The only exception is if this function + returns a non-zero value, in which case, ::commit should not be called. + */ + + // If we can't take the state lock return. + if (!state_lock.trylock()) { + return 1; + } + + adjust_capture_position = 0; + + if (nominally_recording || (_session.get_record_enabled() && _session.get_punch_in())) { + OverlapType ot; + + ot = coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes); + + switch (ot) { + case OverlapNone: + rec_nframes = 0; + break; + + case OverlapInternal: + /* ---------- recrange + |---| transrange + */ + rec_nframes = nframes; + rec_offset = 0; + break; + + case OverlapStart: + /* |--------| recrange + -----| transrange + */ + rec_nframes = transport_frame + nframes - first_recordable_frame; + if (rec_nframes) { + rec_offset = first_recordable_frame - transport_frame; + } + break; + + case OverlapEnd: + /* |--------| recrange + |-------- transrange + */ + rec_nframes = last_recordable_frame - transport_frame; + rec_offset = 0; + break; + + case OverlapExternal: + /* |--------| recrange + -------------- transrange + */ + rec_nframes = last_recordable_frame - last_recordable_frame; + rec_offset = first_recordable_frame - transport_frame; + break; + } + + if (rec_nframes && !was_recording) { + capture_captured = 0; + was_recording = true; + } + } + + + if (can_record && !_last_capture_regions.empty()) { + _last_capture_regions.clear (); + } + + if (nominally_recording || rec_nframes) { + _capture_buf->get_write_vector (&_capture_vector); + + if (rec_nframes <= _capture_vector.len[0]) { + + _current_capture_buffer = _capture_vector.buf[0]; + + /* note: grab the entire port buffer, but only copy what we were supposed to for recording, and use + rec_offset + */ + + // FIXME: midi buffer size? + + // FIXME: reading from a MIDI port is different, can't just memcpy + //memcpy (_current_capture_buffer, _io->input(0)->get_buffer (rec_nframes) + offset + rec_offset, sizeof (RawMidi) * rec_nframes); + assert(_source_port); + for (size_t i=0; i < _source_port->size(); ++i) { + cerr << "DISKSTREAM GOT EVENT " << i << "!!\n"; + } + + if (_source_port->size() == 0) + cerr << "No events :/ (1)\n"; + + + } else { + + jack_nframes_t total = _capture_vector.len[0] + _capture_vector.len[1]; + + if (rec_nframes > total) { + cerr << "DiskOverrun\n"; + //DiskOverrun (); // FIXME + goto out; + } + + // FIXME (see above) + //RawMidi* buf = _io->input (0)->get_buffer (nframes) + offset; + assert(_source_port); + for (size_t i=0; i < _source_port->size(); ++i) { + cerr << "DISKSTREAM GOT EVENT " << i << "!!\n"; + } + if (_source_port->size() == 0) + cerr << "No events :/ (2)\n"; + RawMidi* buf = NULL; // FIXME FIXME FIXME (make it compile) + assert(false); + jack_nframes_t first = _capture_vector.len[0]; + + memcpy (_capture_wrap_buffer, buf, sizeof (RawMidi) * first); + memcpy (_capture_vector.buf[0], buf, sizeof (RawMidi) * first); + memcpy (_capture_wrap_buffer+first, buf + first, sizeof (RawMidi) * (rec_nframes - first)); + memcpy (_capture_vector.buf[1], buf + first, sizeof (RawMidi) * (rec_nframes - first)); + + _current_capture_buffer = _capture_wrap_buffer; + } + } else { + + if (was_recording) { + finish_capture (rec_monitors_input); + } + + } + + if (rec_nframes) { + + /* data will be written to disk */ + + if (rec_nframes == nframes && rec_offset == 0) { + + _current_playback_buffer = _current_capture_buffer; + playback_distance = nframes; + + } else { + + + /* we can't use the capture buffer as the playback buffer, because + we recorded only a part of the current process' cycle data + for capture. + */ + + collect_playback = true; + } + + adjust_capture_position = rec_nframes; + + } else if (nominally_recording) { + + /* can't do actual capture yet - waiting for latency effects to finish before we start*/ + + _current_playback_buffer = _current_capture_buffer; + + playback_distance = nframes; + + } else { + + collect_playback = true; + } + + if (collect_playback) { + + /* we're doing playback */ + + jack_nframes_t necessary_samples; + + /* no varispeed playback if we're recording, because the output .... TBD */ + + if (rec_nframes == 0 && _actual_speed != 1.0f) { + necessary_samples = (jack_nframes_t) floor ((nframes * fabs (_actual_speed))) + 1; + } else { + necessary_samples = nframes; + } + + _playback_buf->get_read_vector (&_playback_vector); + + if (necessary_samples <= _playback_vector.len[0]) { + + _current_playback_buffer = _playback_vector.buf[0]; + + } else { + jack_nframes_t total = _playback_vector.len[0] + _playback_vector.len[1]; + + if (necessary_samples > total) { + cerr << "DiskUnderrun\n"; + //DiskUnderrun (); // FIXME + goto out; + + } else { + + memcpy (_playback_wrap_buffer, _playback_vector.buf[0], + _playback_vector.len[0] * sizeof (RawMidi)); + memcpy (_playback_wrap_buffer + _playback_vector.len[0], _playback_vector.buf[1], + (necessary_samples - _playback_vector.len[0]) * sizeof (RawMidi)); + + _current_playback_buffer = _playback_wrap_buffer; + } + } + +#if 0 + if (rec_nframes == 0 && _actual_speed != 1.0f && _actual_speed != -1.0f) { + + uint64_t phase = last_phase; + jack_nframes_t i = 0; + + // Linearly interpolate into the alt buffer + // using 40.24 fixp maths (swh) + + for (c = channels.begin(); c != channels.end(); ++c) { + + float fr; + ChannelInfo& chan (*c); + + i = 0; + phase = last_phase; + + for (jack_nframes_t outsample = 0; outsample < nframes; ++outsample) { + i = phase >> 24; + fr = (phase & 0xFFFFFF) / 16777216.0f; + chan.speed_buffer[outsample] = + chan._current_playback_buffer[i] * (1.0f - fr) + + chan._current_playback_buffer[i+1] * fr; + phase += phi; + } + + chan._current_playback_buffer = chan.speed_buffer; + } + + playback_distance = i + 1; + last_phase = (phase & 0xFFFFFF); + + } else { + playback_distance = nframes; + } +#endif + + playback_distance = nframes; + + } + + ret = 0; + + out: + _processed = true; + + if (ret) { + + /* we're exiting with failure, so ::commit will not + be called. unlock the state lock. + */ + + state_lock.unlock(); + } + + return ret; } bool @@ -382,23 +802,39 @@ MidiDiskstream::internal_playback_seek (jack_nframes_t distance) } int -MidiDiskstream::read (RawMidi* buf, RawMidi* mixdown_buffer, char * workbuf, jack_nframes_t& start, jack_nframes_t cnt, bool reversed) +MidiDiskstream::read (RawMidi* buf, jack_nframes_t& start, jack_nframes_t cnt, bool reversed) { return 0; } -/* + int -MidiDiskstream::do_refill (RawMidi* mixdown_buffer, float* gain_buffer, char * workbuf) +MidiDiskstream::do_refill_with_alloc () { return 0; -} +} int -MidiDiskstream::do_flush (char * workbuf, bool force_flush) +MidiDiskstream::do_refill () { return 0; } -*/ + +/** Flush pending data to disk. + * + * Important note: this function will write *AT MOST* disk_io_chunk_frames + * of data to disk. it will never write more than that. If it writes that + * much and there is more than that waiting to be written, it will return 1, + * otherwise 0 on success or -1 on failure. + * + * If there is less than disk_io_chunk_frames to be written, no data will be + * written at all unless @a force_flush is true. + */ +int +MidiDiskstream::do_flush (Session::RunContext context, bool force_flush) +{ + return 0; +} + void MidiDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_capture) { @@ -412,6 +848,63 @@ MidiDiskstream::finish_capture (bool rec_monitors_input) void MidiDiskstream::set_record_enabled (bool yn) { + if (!recordable() || !_session.record_enabling_legal()) { + return; + } + + /* can't rec-enable in destructive mode if transport is before start */ + + if (destructive() && yn && _session.transport_frame() < _session.current_start_frame()) { + return; + } + + if (yn && _source_port == 0) { + + /* pick up connections not initiated *from* the IO object + we're associated with. + */ + + get_input_sources (); + } + + /* yes, i know that this not proof against race conditions, but its + good enough. i think. + */ + + if (record_enabled() != yn) { + if (yn) { + engage_record_enable (); + } else { + disengage_record_enable (); + } + } +} + +void +MidiDiskstream::engage_record_enable () +{ + bool rolling = _session.transport_speed() != 0.0f; + + g_atomic_int_set (&_record_enabled, 1); + + if (Config->get_use_hardware_monitoring() && _source_port) { + _source_port->request_monitor_input (!(_session.get_auto_input() && rolling)); + } + + RecordEnableChanged (); /* EMIT SIGNAL */ +} + +void +MidiDiskstream::disengage_record_enable () +{ + g_atomic_int_set (&_record_enabled, 0); + if (Config->get_use_hardware_monitoring()) { + if (_source_port) { + _source_port->request_monitor_input (false); + } + } + + RecordEnableChanged (); /* EMIT SIGNAL */ } XMLNode& @@ -433,16 +926,14 @@ MidiDiskstream::get_state () id().print(buf); node->add_property("id", buf); - if (!_capturing_sources.empty() && _session.get_record_enabled()) { + if (_write_source && _session.get_record_enabled()) { XMLNode* cs_child = new XMLNode (X_("CapturingSources")); XMLNode* cs_grandchild; - for (vector<SMFSource*>::iterator i = _capturing_sources.begin(); i != _capturing_sources.end(); ++i) { - cs_grandchild = new XMLNode (X_("file")); - cs_grandchild->add_property (X_("path"), (*i)->path()); - cs_child->add_child_nocopy (*cs_grandchild); - } + cs_grandchild = new XMLNode (X_("file")); + cs_grandchild->add_property (X_("path"), _write_source->path()); + cs_child->add_child_nocopy (*cs_grandchild); /* store the location where capture will start */ @@ -545,7 +1036,8 @@ MidiDiskstream::set_state (const XMLNode& node) /* make sure this is clear before we do anything else */ - _capturing_sources.clear (); + // FIXME? + //_capturing_source = 0; /* write sources are handled when we handle the input set up of the IO that owns this DS (::non_realtime_input_change()) @@ -559,17 +1051,85 @@ MidiDiskstream::set_state (const XMLNode& node) int MidiDiskstream::use_new_write_source (uint32_t n) { + if (!recordable()) { + return 1; + } + + assert(n == 0); + + if (_write_source) { + + if (SMFSource::is_empty (_write_source->path())) { + _write_source->mark_for_remove (); + _write_source->release(); + delete _write_source; + } else { + _write_source->release(); + _write_source = 0; + } + } + + try { + _write_source = dynamic_cast<SMFSource*>(_session.create_midi_source_for_session (*this)); + if (!_write_source) { + throw failed_constructor(); + } + } + + catch (failed_constructor &err) { + error << string_compose (_("%1:%2 new capture file not initialized correctly"), _name, n) << endmsg; + _write_source = 0; + return -1; + } + + _write_source->use (); + + /* do not remove destructive files even if they are empty */ + + _write_source->set_allow_remove_if_empty (!destructive()); + return 0; } void MidiDiskstream::reset_write_sources (bool mark_write_complete, bool force) { + if (!recordable()) { + return; + } + + if (!destructive()) { + + if (_write_source && mark_write_complete) { + _write_source->mark_streaming_write_completed (); + } + use_new_write_source (); + + } else { + if (_write_source == 0) { + use_new_write_source (); + } + } + + if (destructive()) { + + /* we now have all our write sources set up, so create the + playlist's single region. + */ + + if (_playlist->empty()) { + setup_destructive_playlist (); + } + } } int MidiDiskstream::rename_write_sources () { + if (_write_source != 0) { + _write_source->set_name (_name, destructive()); + /* XXX what to do if this fails ? */ + } return 0; } @@ -586,24 +1146,47 @@ MidiDiskstream::allocate_temporary_buffers () void MidiDiskstream::monitor_input (bool yn) { + if (_source_port) + _source_port->request_monitor_input (yn); + else + cerr << "MidiDiskstream NO SOURCE PORT TO MONITOR\n"; } void MidiDiskstream::set_align_style_from_io () { + bool have_physical = false; + + if (_io == 0) { + return; + } + + get_input_sources (); + + if (_source_port && _source_port->flags() & JackPortIsPhysical) { + have_physical = true; + } + + if (have_physical) { + set_align_style (ExistingMaterial); + } else { + set_align_style (CaptureTime); + } } float MidiDiskstream::playback_buffer_load () const { - return 0; + return (float) ((double) _playback_buf->read_space()/ + (double) _playback_buf->bufsize()); } float MidiDiskstream::capture_buffer_load () const { - return 0; + return (float) ((double) _capture_buf->write_space()/ + (double) _capture_buf->bufsize()); } diff --git a/libs/ardour/midi_playlist.cc b/libs/ardour/midi_playlist.cc index 007856e3a7..db28c06f17 100644 --- a/libs/ardour/midi_playlist.cc +++ b/libs/ardour/midi_playlist.cc @@ -164,71 +164,43 @@ struct RegionSortByLayer } }; +/** FIXME: semantics of return value? */ jack_nframes_t -MidiPlaylist::read (unsigned char *buf, unsigned char *mixdown_buffer, char * workbuf, jack_nframes_t start, +MidiPlaylist::read (RawMidi *buf, RawMidi *mixdown_buffer, jack_nframes_t start, jack_nframes_t cnt, unsigned chan_n) { - jack_nframes_t ret = cnt; - jack_nframes_t end; - jack_nframes_t read_frames; - jack_nframes_t skip_frames; - - /* optimizing this memset() away involves a lot of conditionals - that may well cause more of a hit due to cache misses - and related stuff than just doing this here. - - it would be great if someone could measure this - at some point. - - one way or another, parts of the requested area - that are not written to by Region::region_at() - for all Regions that cover the area need to be - zeroed. - */ - - memset (buf, 0, sizeof (unsigned char) * cnt); - /* this function is never called from a realtime thread, so its OK to block (for short intervals). */ Glib::Mutex::Lock rm (region_lock); - end = start + cnt - 1; + jack_nframes_t ret = 0; + jack_nframes_t end = start + cnt - 1; + jack_nframes_t read_frames = 0; + jack_nframes_t skip_frames = 0; - read_frames = 0; - skip_frames = 0; _read_data_count = 0; - map<uint32_t,vector<Region*> > relevant_regions; - vector<uint32_t> relevant_layers; + vector<MidiRegion*> regs; // relevent regions overlapping start <--> end for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { - if ((*i)->coverage (start, end) != OverlapNone) { - - relevant_regions[(*i)->layer()].push_back (*i); - relevant_layers.push_back ((*i)->layer()); + MidiRegion* const mr = dynamic_cast<MidiRegion*>(*i); + if (mr && mr->coverage (start, end) != OverlapNone) { + regs.push_back(mr); } } - // RegionSortByLayer layer_cmp; - // relevant_regions.sort (layer_cmp); - - - for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) { - - // FIXME: Should be vector<MidiRegion*> - vector<Region*>& r (relevant_regions[*l]); - - for (vector<Region*>::iterator i = r.begin(); i != r.end(); ++i) { - MidiRegion* const mr = dynamic_cast<MidiRegion*>(*i); - assert(mr); - mr->read_at (buf, mixdown_buffer, workbuf, start, cnt, chan_n, read_frames, skip_frames); - _read_data_count += mr->read_data_count(); - } + RegionSortByLayer layer_cmp; + sort(regs.begin(), regs.end(), layer_cmp); + for (vector<MidiRegion*>::iterator i = regs.begin(); i != regs.end(); ++i) { + (*i)->read_at (buf, mixdown_buffer, start, cnt, chan_n, read_frames, skip_frames); + ret += (*i)->read_data_count(); } + _read_data_count += ret; + return ret; } diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc new file mode 100644 index 0000000000..e785710b01 --- /dev/null +++ b/libs/ardour/midi_port.cc @@ -0,0 +1,102 @@ +/* + Copyright (C) 2006 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. +*/ + +#include <cassert> +#include <ardour/midi_port.h> +#include <ardour/data_type.h> +#include <iostream> + +using namespace ARDOUR; +using namespace std; + +MidiPort::MidiPort(jack_port_t* p) + : Port(p) + , _buffer(NULL) + , _nframes_this_cycle(0) +{ + DataType dt(_type); + assert(dt == DataType::MIDI); + + reset(); + + _buffer = new MidiBuffer(4096); // FIXME FIXME FIXME +} + + +MidiPort::~MidiPort() +{ + delete _buffer; +} + +void +MidiPort::cycle_start (jack_nframes_t nframes) +{ + _nframes_this_cycle = nframes; + + if (_flags & JackPortIsOutput) { + _buffer->set_size(0); + return; + } + + // We're an input - copy Jack events to internal buffer + + void* jack_buffer = jack_port_get_buffer(_port, nframes); + + const jack_nframes_t event_count + = jack_midi_port_get_info(jack_buffer, nframes)->event_count; + + assert(event_count < _buffer->capacity()); + + for (jack_nframes_t i=0; i < event_count; ++i) { + jack_midi_event_t* const ev = &_buffer->data()[i]; + jack_midi_event_get(ev, jack_buffer, i, nframes); + + // Convert note ons with velocity 0 to proper note offs + // FIXME: Jack MIDI should guarantee this - does it? + //if (ev->buffer[0] == MIDI_CMD_NOTE_ON && ev->buffer[2] == 0) + // ev->buffer[0] = MIDI_CMD_NOTE_OFF; + } + + _buffer->set_size(event_count); + + if (_buffer->size() > 0) + cerr << "MIDIPort got " << event_count << " events." << endl; +} + +void +MidiPort::cycle_end() +{ + if (_flags & JackPortIsInput) { + _nframes_this_cycle = 0; // catch any oopses + return; + } + + // We're an output - copy events from internal buffer to Jack buffer + + void* jack_buffer = jack_port_get_buffer(_port, _nframes_this_cycle); + + const jack_nframes_t event_count = _buffer->size(); + + jack_midi_clear_buffer(jack_buffer, _nframes_this_cycle); + for (jack_nframes_t i=0; i < event_count; ++i) { + const jack_midi_event_t& ev = _buffer->data()[i]; + jack_midi_event_write(jack_buffer, ev.time, ev.buffer, ev.size, _nframes_this_cycle); + } + + _nframes_this_cycle = 0; // catch oopses +} diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc index d78506c1fc..0902337030 100644 --- a/libs/ardour/midi_region.cc +++ b/libs/ardour/midi_region.cc @@ -1,6 +1,5 @@ /* - Copyright (C) 2006 Paul Davis - Written by Dave Robillard, 2006 + Copyright (C) 2000-2006 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 @@ -15,6 +14,8 @@ 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. + + $Id: midiregion.cc 746 2006-08-02 02:44:23Z drobilla $ */ #include <cmath> @@ -37,6 +38,7 @@ #include <ardour/dB.h> #include <ardour/playlist.h> #include <ardour/midi_source.h> +#include <ardour/types.h> #include "i18n.h" #include <locale.h> @@ -44,20 +46,10 @@ using namespace std; using namespace ARDOUR; -MidiRegionState::MidiRegionState (string why) - : RegionState (why) -{ -} - +/** Basic MidiRegion constructor (one channel) */ MidiRegion::MidiRegion (MidiSource& src, jack_nframes_t start, jack_nframes_t length, bool announce) - : Region (start, length, PBD::basename_nosuffix(src.name()), 0, Region::Flag(Region::DefaultFlags|Region::External)) + : Region (src, start, length, PBD::basename_nosuffix(src.name()), 0, Region::Flag(Region::DefaultFlags|Region::External)) { - /* basic MidiRegion constructor */ - - sources.push_back (&src); - master_sources.push_back (&src); - src.GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted)); - save_state ("initial state"); if (announce) { @@ -65,15 +57,10 @@ MidiRegion::MidiRegion (MidiSource& src, jack_nframes_t start, jack_nframes_t le } } +/* Basic MidiRegion constructor (one channel) */ MidiRegion::MidiRegion (MidiSource& src, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Flag flags, bool announce) - : Region (start, length, name, layer, flags) + : Region (src, start, length, name, layer, flags) { - /* basic MidiRegion constructor */ - - sources.push_back (&src); - master_sources.push_back (&src); - src.GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted)); - save_state ("initial state"); if (announce) { @@ -81,75 +68,40 @@ MidiRegion::MidiRegion (MidiSource& src, jack_nframes_t start, jack_nframes_t le } } +/* Basic MidiRegion constructor (many channels) */ MidiRegion::MidiRegion (SourceList& srcs, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Flag flags, bool announce) - : Region (start, length, name, layer, flags) + : Region (srcs, start, length, name, layer, flags) { - /* basic MidiRegion constructor */ -#if 0 - for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) { - sources.push_back (*i); - master_sources.push_back (*i); - (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted)); - } - -{ - /* create a new MidiRegion, that is part of an existing one */ - - set<MidiSource*> unique_srcs; + save_state ("initial state"); - for (SourceList::const_iterator i= other.sources.begin(); i != other.sources.end(); ++i) { - sources.push_back (*i); - (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted)); - unique_srcs.insert (*i); + if (announce) { + CheckNewRegion (this); /* EMIT SIGNAL */ } +} - for (SourceList::const_iterator i = other.master_sources.begin(); i != other.master_sources.end(); ++i) { - if (unique_srcs.find (*i) == unique_srcs.end()) { - (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted)); - } - master_sources.push_back (*i); - } +/** Create a new MidiRegion, that is part of an existing one */ +MidiRegion::MidiRegion (const MidiRegion& other, jack_nframes_t offset, jack_nframes_t length, const string& name, layer_t layer, Flag flags, bool announce) + : Region (other, offset, length, name, layer, flags) +{ save_state ("initial state"); if (announce) { CheckNewRegion (this); /* EMIT SIGNAL */ } -#endif } MidiRegion::MidiRegion (const MidiRegion &other) : Region (other) { - /* Pure copy constructor */ - - set<MidiSource*> unique_srcs; - - for (SourceList::const_iterator i = other.sources.begin(); i != other.sources.end(); ++i) { - sources.push_back (*i); - (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted)); - unique_srcs.insert (*i); - } - - for (SourceList::const_iterator i = other.master_sources.begin(); i != other.master_sources.end(); ++i) { - master_sources.push_back (*i); - if (unique_srcs.find (*i) == unique_srcs.end()) { - (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted)); - } - } - save_state ("initial state"); /* NOTE: no CheckNewRegion signal emitted here. This is the copy constructor */ } MidiRegion::MidiRegion (MidiSource& src, const XMLNode& node) - : Region (node) + : Region (src, node) { - sources.push_back (&src); - master_sources.push_back (&src); - src.GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted)); - if (set_state (node)) { throw failed_constructor(); } @@ -160,25 +112,8 @@ MidiRegion::MidiRegion (MidiSource& src, const XMLNode& node) } MidiRegion::MidiRegion (SourceList& srcs, const XMLNode& node) - : Region (node) + : Region (srcs, node) { - /* basic MidiRegion constructor */ - - set<MidiSource*> unique_srcs; - - for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) { - sources.push_back (*i); - (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted)); - unique_srcs.insert (*i); - } - - for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) { - master_sources.push_back (*i); - if (unique_srcs.find (*i) == unique_srcs.end()) { - (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted)); - } - } - if (set_state (node)) { throw failed_constructor(); } @@ -196,7 +131,7 @@ MidiRegion::~MidiRegion () StateManager::State* MidiRegion::state_factory (std::string why) const { - MidiRegionState* state = new MidiRegionState (why); + RegionState* state = new RegionState (why); Region::store_state (*state); @@ -206,8 +141,7 @@ MidiRegion::state_factory (std::string why) const Change MidiRegion::restore_state (StateManager::State& sstate) { - MidiRegionState* state = dynamic_cast<MidiRegionState*> (&sstate); - + RegionState* state = dynamic_cast<RegionState*> (&sstate); Change what_changed = Region::restore_and_return_flags (*state); if (_flags != Flag (state->_flags)) { @@ -215,11 +149,8 @@ MidiRegion::restore_state (StateManager::State& sstate) //uint32_t old_flags = _flags; _flags = Flag (state->_flags); - } - /* XXX need a way to test stored state versus current for envelopes */ - what_changed = Change (what_changed); return what_changed; @@ -231,66 +162,23 @@ MidiRegion::get_memento() const return sigc::bind (mem_fun (*(const_cast<MidiRegion *> (this)), &StateManager::use_state), _current_state_id); } -bool -MidiRegion::verify_length (jack_nframes_t len) -{ - for (uint32_t n=0; n < sources.size(); ++n) { - if (_start > sources[n]->length() - len) { - return false; - } - } - return true; -} - -bool -MidiRegion::verify_start_and_length (jack_nframes_t new_start, jack_nframes_t new_length) -{ - for (uint32_t n=0; n < sources.size(); ++n) { - if (new_length > sources[n]->length() - new_start) { - return false; - } - } - return true; -} -bool -MidiRegion::verify_start (jack_nframes_t pos) -{ - for (uint32_t n=0; n < sources.size(); ++n) { - if (pos > sources[n]->length() - _length) { - return false; - } - } - return true; -} - -bool -MidiRegion::verify_start_mutable (jack_nframes_t& new_start) -{ - for (uint32_t n=0; n < sources.size(); ++n) { - if (new_start > sources[n]->length() - _length) { - new_start = sources[n]->length() - _length; - } - } - return true; -} - jack_nframes_t -MidiRegion::read_at (unsigned char *buf, unsigned char *mixdown_buffer, char * workbuf, jack_nframes_t position, +MidiRegion::read_at (RawMidi *out, RawMidi* mix_buf, jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n, jack_nframes_t read_frames, jack_nframes_t skip_frames) const { - return _read_at (sources, buf, mixdown_buffer, workbuf, position, cnt, chan_n, read_frames, skip_frames); + return _read_at (_sources, out, position, cnt, chan_n, read_frames, skip_frames); } jack_nframes_t -MidiRegion::master_read_at (unsigned char *buf, unsigned char *mixdown_buffer, char * workbuf, jack_nframes_t position, +MidiRegion::master_read_at (RawMidi *out, RawMidi* mix_buf, jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n) const { - return _read_at (master_sources, buf, mixdown_buffer, workbuf, position, cnt, chan_n, 0, 0); + return _read_at (_master_sources, out, position, cnt, chan_n, 0, 0); } jack_nframes_t -MidiRegion::_read_at (const SourceList& srcs, unsigned char *buf, unsigned char *mixdown_buffer, char * workbuf, +MidiRegion::_read_at (const SourceList& srcs, RawMidi *buf, jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n, jack_nframes_t read_frames, jack_nframes_t skip_frames) const { @@ -300,9 +188,7 @@ MidiRegion::_read_at (const SourceList& srcs, unsigned char *buf, unsigned char /* precondition: caller has verified that we cover the desired section */ - if (chan_n >= sources.size()) { - return 0; /* read nothing */ - } + assert(chan_n == 0); if (position < _position) { internal_offset = 0; @@ -322,12 +208,8 @@ MidiRegion::_read_at (const SourceList& srcs, unsigned char *buf, unsigned char return 0; /* read nothing */ } - if (opaque()) { - /* overwrite whatever is there */ - mixdown_buffer = buf + buf_offset; - } else { - mixdown_buffer += buf_offset; - } + // FIXME: non-opaque MIDI regions not yet supported + assert(opaque()); if (muted()) { return 0; /* read nothing */ @@ -335,39 +217,21 @@ MidiRegion::_read_at (const SourceList& srcs, unsigned char *buf, unsigned char _read_data_count = 0; - if (srcs[chan_n]->read (mixdown_buffer, _start + internal_offset, to_read, workbuf) != to_read) { + MidiSource& src = midi_source(chan_n); + if (src.read (buf, _start + internal_offset, to_read) != to_read) { return 0; /* "read nothing" */ } - _read_data_count += srcs[chan_n]->read_data_count(); - - if (!opaque()) { + _read_data_count += src.read_data_count(); - /* gack. the things we do for users. - */ - - buf += buf_offset; - - for (jack_nframes_t n = 0; n < to_read; ++n) { - buf[n] += mixdown_buffer[n]; - } - } - return to_read; } XMLNode& -MidiRegion::get_state () -{ - return state (true); -} - -XMLNode& MidiRegion::state (bool full) { XMLNode& node (Region::state (full)); -#if 0 -//XMLNode *child; + XMLNode *child; char buf[64]; char buf2[64]; LocaleGuard lg (X_("POSIX")); @@ -375,19 +239,25 @@ MidiRegion::state (bool full) snprintf (buf, sizeof (buf), "0x%x", (int) _flags); node.add_property ("flags", buf); - for (uint32_t n=0; n < sources.size(); ++n) { + for (uint32_t n=0; n < _sources.size(); ++n) { snprintf (buf2, sizeof(buf2), "source-%d", n); - snprintf (buf, sizeof(buf), "%" PRIu64, sources[n]->id()); + _sources[n]->id().print (buf); node.add_property (buf2, buf); } - snprintf (buf, sizeof (buf), "%u", (uint32_t) sources.size()); + snprintf (buf, sizeof (buf), "%u", (uint32_t) _sources.size()); node.add_property ("channels", buf); + child = node.add_child ("Envelope"); + + if ( ! full) { + child->add_property ("default", "yes"); + } + if (full && _extra_xml) { node.add_child_copy (*_extra_xml); } -#endif + return node; } @@ -402,31 +272,51 @@ MidiRegion::set_state (const XMLNode& node) if ((prop = node.property ("flags")) != 0) { _flags = Flag (strtol (prop->value().c_str(), (char **) 0, 16)); - - _flags = Flag (_flags & ~Region::LeftOfSplit); - _flags = Flag (_flags & ~Region::RightOfSplit); } - /* Now find envelope description and other misc child items */ - + /* Now find child items */ for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) { XMLNode *child; //XMLProperty *prop; child = (*niter); + + /** Hello, children */ } return 0; } +void +MidiRegion::recompute_at_end () +{ + /* our length has changed + * (non destructively) "chop" notes that pass the end boundary, to + * prevent stuck notes. + */ +} + +void +MidiRegion::recompute_at_start () +{ + /* as above, but the shift was from the front + * maybe bump currently active note's note-ons up so they sound here? + * that could be undesireable in certain situations though.. maybe + * remove the note entirely, including it's note off? something needs to + * be done to keep the played MIDI sane to avoid messing up voices of + * polyhonic things etc........ + */ +} + int MidiRegion::separate_by_channel (Session& session, vector<MidiRegion*>& v) const { +#if 0 SourceList srcs; string new_name; - for (SourceList::const_iterator i = master_sources.begin(); i != master_sources.end(); ++i) { + for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) { srcs.clear (); srcs.push_back (*i); @@ -441,185 +331,14 @@ MidiRegion::separate_by_channel (Session& session, vector<MidiRegion*>& v) const v.push_back (new MidiRegion (srcs, _start, _length, new_name, _layer, _flags)); } - - return 0; -} - -void -MidiRegion::source_deleted (Source* ignored) -{ - delete this; -} - -void -MidiRegion::lock_sources () -{ - SourceList::iterator i; - set<MidiSource*> unique_srcs; - - for (i = sources.begin(); i != sources.end(); ++i) { - unique_srcs.insert (*i); - (*i)->use (); - } - - for (i = master_sources.begin(); i != master_sources.end(); ++i) { - if (unique_srcs.find (*i) == unique_srcs.end()) { - (*i)->use (); - } - } -} - -void -MidiRegion::unlock_sources () -{ - SourceList::iterator i; - set<MidiSource*> unique_srcs; - - for (i = sources.begin(); i != sources.end(); ++i) { - unique_srcs.insert (*i); - (*i)->release (); - } - - for (i = master_sources.begin(); i != master_sources.end(); ++i) { - if (unique_srcs.find (*i) == unique_srcs.end()) { - (*i)->release (); - } - } -} - -vector<string> -MidiRegion::master_source_names () -{ - SourceList::iterator i; - - vector<string> names; - for (i = master_sources.begin(); i != master_sources.end(); ++i) { - names.push_back((*i)->name()); - } - - return names; -} - -bool -MidiRegion::source_equivalent (const Region& o) const -{ - const MidiRegion* other = dynamic_cast<const MidiRegion*>(&o); - if (!other) - return false; - - SourceList::const_iterator i; - SourceList::const_iterator io; - - for (i = sources.begin(), io = other->sources.begin(); i != sources.end() && io != other->sources.end(); ++i, ++io) { - if ((*i)->id() != (*io)->id()) { - return false; - } - } - - for (i = master_sources.begin(), io = other->master_sources.begin(); i != master_sources.end() && io != other->master_sources.end(); ++i, ++io) { - if ((*i)->id() != (*io)->id()) { - return false; - } - } - - return true; -} - -#if 0 -int -MidiRegion::exportme (Session& session, AudioExportSpecification& spec) -{ - const jack_nframes_t blocksize = 4096; - jack_nframes_t to_read; - int status = -1; - - spec.channels = sources.size(); - - if (spec.prepare (blocksize, session.frame_rate())) { - goto out; - } - - spec.pos = 0; - spec.total_frames = _length; - - while (spec.pos < _length && !spec.stop) { - - - /* step 1: interleave */ - - to_read = min (_length - spec.pos, blocksize); - - if (spec.channels == 1) { - - if (sources.front()->read (spec.dataF, _start + spec.pos, to_read, 0) != to_read) { - goto out; - } - - } else { - - Sample buf[blocksize]; - - for (uint32_t chan = 0; chan < spec.channels; ++chan) { - - if (sources[chan]->read (buf, _start + spec.pos, to_read, 0) != to_read) { - goto out; - } - - for (jack_nframes_t x = 0; x < to_read; ++x) { - spec.dataF[chan+(x*spec.channels)] = buf[x]; - } - } - } - - if (spec.process (to_read)) { - goto out; - } - - spec.pos += to_read; - spec.progress = (double) spec.pos /_length; - - } - - status = 0; - - out: - spec.running = false; - spec.status = status; - spec.clear(); - - return status; -} -#endif - -Region* -MidiRegion::get_parent() -{ -#if 0 - Region* r = 0; - - if (_playlist) { - r = _playlist->session().find_whole_file_parent (*this); - } - - return r; #endif - return NULL; + return -1; } - -bool -MidiRegion::speed_mismatch (float sr) const +MidiSource& +MidiRegion::midi_source (uint32_t n) const { -#if 0 - if (sources.empty()) { - /* impossible, but ... */ - return false; - } - - float fsr = sources.front()->sample_rate(); - - return fsr == sr; -#endif - return false; + // Guaranteed to succeed (use a static cast?) + return dynamic_cast<MidiSource&>(source(n)); } diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc index f9fc8dd8ec..4cda0f6ebd 100644 --- a/libs/ardour/midi_source.cc +++ b/libs/ardour/midi_source.cc @@ -90,44 +90,26 @@ MidiSource::set_state (const XMLNode& node) } jack_nframes_t -MidiSource::read (unsigned char *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const +MidiSource::read (RawMidi* dst, jack_nframes_t start, jack_nframes_t cnt) const { - //Glib::Mutex::Lock lm (_lock); - //return read_unlocked (dst, start, cnt, workbuf); - return 0; + Glib::Mutex::Lock lm (_lock); + return read_unlocked (dst, start, cnt); } jack_nframes_t -MidiSource::write (unsigned char *dst, jack_nframes_t cnt, char * workbuf) +MidiSource::write (RawMidi* dst, jack_nframes_t cnt) { - //Glib::Mutex::Lock lm (_lock); - //return write_unlocked (dst, cnt, workbuf); - return 0; + Glib::Mutex::Lock lm (_lock); + return write_unlocked (dst, cnt); } - bool MidiSource::file_changed (string path) { struct stat stat_file; - //struct stat stat_peak; int e1 = stat (path.c_str(), &stat_file); - //int e2 = stat (peak_path(path).c_str(), &stat_peak); - if (!e1){//&& !e2 && stat_file.st_mtime > stat_peak.st_mtime){ - return true; - } else { - return false; - } -} - - -void -MidiSource::update_length (jack_nframes_t pos, jack_nframes_t cnt) -{ - if (pos + cnt > _length) { - _length = pos+cnt; - } + return ( !e1 ); } diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc index f37ba9f190..93eba11a30 100644 --- a/libs/ardour/midi_track.cc +++ b/libs/ardour/midi_track.cc @@ -507,6 +507,15 @@ MidiTrack::silent_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack return midi_diskstream().process (_session.transport_frame() + offset, nframes, offset, can_record, rec_monitors_input); } +void +MidiTrack::process_output_buffers (vector<Sample*>& bufs, uint32_t nbufs, + jack_nframes_t start_frame, jack_nframes_t end_frame, + jack_nframes_t nframes, jack_nframes_t offset, bool with_redirects, int declick, + bool meter) +{ + // Do nothing (just bypass the Route version to avoid flaming death) +} + int MidiTrack::set_name (string str, void *src) { @@ -530,7 +539,7 @@ MidiTrack::set_name (string str, void *src) } int -MidiTrack::export_stuff (vector<unsigned char*>& buffers, char * workbuf, uint32_t nbufs, jack_nframes_t start, jack_nframes_t nframes) +MidiTrack::export_stuff (vector<unsigned char*>& buffers, uint32_t nbufs, jack_nframes_t start, jack_nframes_t nframes) { return 0; } diff --git a/libs/ardour/panner.cc b/libs/ardour/panner.cc index 8336c4697c..f866b5ae10 100644 --- a/libs/ardour/panner.cc +++ b/libs/ardour/panner.cc @@ -1258,10 +1258,10 @@ Panner::set_state (const XMLNode& node) float x, y; prop = (*niter)->property (X_("x")); - sscanf (prop->value().c_str(), "%.12g", &x); + sscanf (prop->value().c_str(), "%g", &x); prop = (*niter)->property (X_("y")); - sscanf (prop->value().c_str(), "%.12g", &y); + sscanf (prop->value().c_str(), "%g", &y); outputs.push_back (Output (x, y)); } diff --git a/libs/ardour/plugin.cc b/libs/ardour/plugin.cc index 8ea95b8903..bedc32a0b3 100644 --- a/libs/ardour/plugin.cc +++ b/libs/ardour/plugin.cc @@ -244,25 +244,25 @@ Plugin::save_preset (string name, string domain) } PluginPtr -ARDOUR::find_plugin(Session& session, string name, long unique_id, PluginInfo::Type type) +ARDOUR::find_plugin(Session& session, string name, long unique_id, PluginType type) { PluginManager *mgr = PluginManager::the_manager(); PluginInfoList plugs; switch (type) { - case PluginInfo::LADSPA: + case ARDOUR::LADSPA: plugs = mgr->ladspa_plugin_info(); break; #ifdef VST_SUPPORT - case PluginInfo::VST: + case ARDOUR::VST: plugs = mgr->vst_plugin_info(); unique_id = 0; // VST plugins don't have a unique id. break; #endif #ifdef HAVE_COREAUDIO - case PluginInfo::AudioUnit: + case ARDOUR::AudioUnit: plugs = AUPluginInfo::discover (); unique_id = 0; // Neither do AU. break; diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc index 2a753617e8..5b3a4658a8 100644 --- a/libs/ardour/plugin_manager.cc +++ b/libs/ardour/plugin_manager.cc @@ -254,7 +254,7 @@ PluginManager::ladspa_discover (string path) info->index = i; info->n_inputs = 0; info->n_outputs = 0; - info->type = PluginInfo::LADSPA; + info->type = ARDOUR::LADSPA; info->unique_id = descriptor->UniqueID; for (uint32_t n=0; n < descriptor->PortCount; ++n) { @@ -397,7 +397,7 @@ PluginManager::vst_discover (string path) info->index = 0; info->n_inputs = finfo->numInputs; info->n_outputs = finfo->numOutputs; - info->type = PluginInfo::VST; + info->type = ARDOUR::VST; _vst_plugin_info.push_back (info); fst_free_info (finfo); diff --git a/libs/ardour/port.cc b/libs/ardour/port.cc index 7ec0d5a05a..5f8b454f0f 100644 --- a/libs/ardour/port.cc +++ b/libs/ardour/port.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2002 Paul Davis + Copyright (C) 2002-2006 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 @@ -18,13 +18,16 @@ $Id$ */ -#include "ardour/port.h" +#include <ardour/port.h> using namespace ARDOUR; using namespace std; Port::Port (jack_port_t *p) : _port (p) + , _metering(0) + , _last_monitor(false) + , _silent(false) { if (_port == 0) { throw failed_constructor(); @@ -40,13 +43,8 @@ Port::Port (jack_port_t *p) void Port::reset () { - reset_buffer (); - _last_monitor = false; _silent = false; - _metering = 0; - - reset_meters (); } int diff --git a/libs/ardour/port_set.cc b/libs/ardour/port_set.cc new file mode 100644 index 0000000000..22fb032c09 --- /dev/null +++ b/libs/ardour/port_set.cc @@ -0,0 +1,111 @@ +/* + Copyright (C) 2006 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. +*/ + +#include <ardour/port_set.h> + +namespace ARDOUR { + +PortSet::PortSet() +{ + for (size_t i=0; i < DataType::num_types; ++i) + _ports.push_back( PortVec() ); +} + +static bool sort_ports_by_name (Port* a, Port* b) +{ + return (a->name() < b->name()); +} + +void +PortSet::add_port(Port* port) +{ + const size_t list_index = port->type().to_index(); + assert(list_index < _ports.size()); + + PortVec& v = _ports[list_index]; + + v.push_back(port); + sort(v.begin(), v.end(), sort_ports_by_name); + + _chan_count.set_count(port->type(), _chan_count.get_count(port->type()) + 1); + + assert(_chan_count.get_count(port->type()) == _ports[port->type().to_index()].size()); +} + + +/** Get the total number of ports (of all types) in the PortSet + */ +size_t +PortSet::num_ports() const +{ + size_t ret = 0; + + for (std::vector<PortVec>::const_iterator l = _ports.begin(); l != _ports.end(); ++l) + ret += (*l).size(); + + return ret; +} + +bool +PortSet::contains(const Port* port) const +{ + for (std::vector<PortVec>::const_iterator l = _ports.begin(); l != _ports.end(); ++l) + if (find((*l).begin(), (*l).end(), port) != (*l).end()) + return true; + + return false; +} + +Port* +PortSet::port(size_t n) const +{ + // This is awesome + + size_t size_so_far = 0; + + for (std::vector<PortVec>::const_iterator l = _ports.begin(); l != _ports.end(); ++l) { + if (n < size_so_far + (*l).size()) + return (*l)[n - size_so_far]; + else + size_so_far += (*l).size(); + } + + return NULL; // n out of range +} + +Port* +PortSet::nth_port_of_type(DataType type, size_t n) const +{ + const PortVec& v = _ports[type.to_index()]; + assert(n < v.size()); + return v[n]; +} + +AudioPort* +PortSet::nth_audio_port(size_t n) const +{ + return dynamic_cast<AudioPort*>(nth_port_of_type(DataType::AUDIO, n)); +} + +MidiPort* +PortSet::nth_midi_port(size_t n) const +{ + return dynamic_cast<MidiPort*>(nth_port_of_type(DataType::MIDI, n)); +} + +} // namepace ARDOUR diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index 037c844324..03a4d1d2a3 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -32,6 +32,7 @@ #include <ardour/region.h> #include <ardour/playlist.h> #include <ardour/session.h> +#include <ardour/source.h> #include "i18n.h" @@ -49,63 +50,124 @@ Change Region::HiddenChanged = ARDOUR::new_change (); sigc::signal<void,Region *> Region::CheckNewRegion; -Region::Region (jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Region::Flag flags) +/** Basic Region constructor (single source) */ +Region::Region (Source& src, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Region::Flag flags) + : _name(name) + , _flags(flags) + , _start(start) + , _length(length) + , _position(0) + , _sync_position(_start) + , _layer(layer) + , _first_edit(EditChangesNothing) + , _frozen(0) + , _read_data_count(0) + , _pending_changed(Change (0)) + , _last_layer_op(0) + , _playlist(0) { - /* basic Region constructor */ + _current_state_id = 0; + + _sources.push_back (&src); + _master_sources.push_back (&src); + src.GoingAway.connect (mem_fun (*this, &Region::source_deleted)); - _flags = flags; - _playlist = 0; - _read_data_count = 0; - _frozen = 0; - pending_changed = Change (0); + assert(_sources.size() > 0); +} - _name = name; - _start = start; - _sync_position = _start; - _length = length; - _position = 0; - _layer = layer; +/** Basic Region constructor (many sources) */ +Region::Region (SourceList& srcs, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Region::Flag flags) + : _name(name) + , _flags(flags) + , _start(start) + , _length(length) + , _position(0) + , _sync_position(_start) + , _layer(layer) + , _first_edit(EditChangesNothing) + , _frozen(0) + , _read_data_count(0) + , _pending_changed(Change (0)) + , _last_layer_op(0) + , _playlist(0) +{ _current_state_id = 0; - _read_data_count = 0; - _first_edit = EditChangesNothing; - _last_layer_op = 0; + + set<Source*> unique_srcs; + + for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) { + _sources.push_back (*i); + (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted)); + unique_srcs.insert (*i); + } + + for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) { + _master_sources.push_back (*i); + if (unique_srcs.find (*i) == unique_srcs.end()) { + (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted)); + } + } + + assert(_sources.size() > 0); } +/** Create a new Region from part of an existing one */ Region::Region (const Region& other, jack_nframes_t offset, jack_nframes_t length, const string& name, layer_t layer, Flag flags) + : _name(name) + , _flags(Flag(flags & ~(Locked|WholeFile|Hidden))) + , _start(other._start + offset) + , _length(length) + , _position(0) + , _sync_position(_start) + , _layer(layer) + , _first_edit(EditChangesNothing) + , _frozen(0) + , _read_data_count(0) + , _pending_changed(Change (0)) + , _last_layer_op(0) + , _playlist(0) { - /* create a new Region from part of an existing one */ + _current_state_id = 0; + + if (other._sync_position < offset) + _sync_position = other._sync_position; - _frozen = 0; - pending_changed = Change (0); - _playlist = 0; - _read_data_count = 0; + set<Source*> unique_srcs; - _start = other._start + offset; - if (other._sync_position < offset) { - _sync_position = other._sync_position; - } else { - _sync_position = _start; + for (SourceList::const_iterator i= other._sources.begin(); i != other._sources.end(); ++i) { + _sources.push_back (*i); + (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted)); + unique_srcs.insert (*i); } - _length = length; - _name = name; - _position = 0; - _layer = layer; - _flags = Flag (flags & ~(Locked|WholeFile|Hidden)); - _current_state_id = 0; - _first_edit = EditChangesNothing; - _last_layer_op = 0; + + for (SourceList::const_iterator i = other._master_sources.begin(); i != other._master_sources.end(); ++i) { + if (unique_srcs.find (*i) == unique_srcs.end()) { + (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted)); + } + _master_sources.push_back (*i); + } + + assert(_sources.size() > 0); } +/** Pure copy constructor */ Region::Region (const Region &other) + : _name(other._name) + , _flags(Flag(other._flags & ~Locked)) + , _start(other._start) + , _length(other._length) + , _position(other._position) + , _sync_position(other._sync_position) + , _layer(other._layer) + , _first_edit(EditChangesID) + , _frozen(0) + , _read_data_count(0) + , _pending_changed(Change(0)) + , _last_layer_op(other._last_layer_op) + , _playlist(0) { - /* Pure copy constructor */ - - _frozen = 0; - pending_changed = Change (0); - _playlist = 0; - _read_data_count = 0; - - _first_edit = EditChangesID; + _current_state_id = 0; + other._first_edit = EditChangesName; if (other._extra_xml) { @@ -114,36 +176,88 @@ Region::Region (const Region &other) _extra_xml = 0; } - _start = other._start; - _sync_position = other._sync_position; - _length = other._length; - _name = other._name; - _position = other._position; - _layer = other._layer; - _flags = Flag (other._flags & ~Locked); + set<Source*> unique_srcs; + + for (SourceList::const_iterator i = other._sources.begin(); i != other._sources.end(); ++i) { + _sources.push_back (*i); + (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted)); + unique_srcs.insert (*i); + } + + for (SourceList::const_iterator i = other._master_sources.begin(); i != other._master_sources.end(); ++i) { + _master_sources.push_back (*i); + if (unique_srcs.find (*i) == unique_srcs.end()) { + (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted)); + } + } + + assert(_sources.size() > 0); +} + +Region::Region (SourceList& srcs, const XMLNode& node) + : _name(X_("error: XML did not reset this")) + , _flags(Flag(0)) + , _start(0) + , _length(0) + , _position(0) + , _sync_position(_start) + , _layer(0) + , _first_edit(EditChangesNothing) + , _frozen(0) + , _read_data_count(0) + , _pending_changed(Change(0)) + , _last_layer_op(0) + , _playlist(0) + +{ + set<Source*> unique_srcs; + + for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) { + _sources.push_back (*i); + (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted)); + unique_srcs.insert (*i); + } + + for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) { + _master_sources.push_back (*i); + if (unique_srcs.find (*i) == unique_srcs.end()) { + (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted)); + } + } + _current_state_id = 0; - _last_layer_op = other._last_layer_op; -} - -Region::Region (const XMLNode& node) -{ - _frozen = 0; - pending_changed = Change (0); - _playlist = 0; - _read_data_count = 0; - _start = 0; - _sync_position = _start; - _length = 0; - _name = X_("error: XML did not reset this"); - _position = 0; - _layer = 0; - _flags = Flag (0); + + if (set_state (node)) { + throw failed_constructor(); + } + + assert(_sources.size() > 0); +} + +Region::Region (Source& src, const XMLNode& node) + : _name(X_("error: XML did not reset this")) + , _flags(Flag(0)) + , _start(0) + , _length(0) + , _position(0) + , _sync_position(_start) + , _layer(0) + , _first_edit(EditChangesNothing) + , _frozen(0) + , _read_data_count(0) + , _pending_changed(Change(0)) + , _last_layer_op(0) + , _playlist(0) +{ + _sources.push_back (&src); + _current_state_id = 0; - _first_edit = EditChangesNothing; if (set_state (node)) { throw failed_constructor(); } + + assert(_sources.size() > 0); } Region::~Region () @@ -175,7 +289,7 @@ Region::restore_and_return_flags (RegionState& state) Change what_changed = Change (0); { - Glib::Mutex::Lock lm (lock); + Glib::Mutex::Lock lm (_lock); if (_start != state._start) { what_changed = Change (what_changed|StartChanged); @@ -944,15 +1058,15 @@ Region::thaw (const string& why) Change what_changed = Change (0); { - Glib::Mutex::Lock lm (lock); + Glib::Mutex::Lock lm (_lock); if (_frozen && --_frozen > 0) { return; } - if (pending_changed) { - what_changed = pending_changed; - pending_changed = Change (0); + if (_pending_changed) { + what_changed = _pending_changed; + _pending_changed = Change (0); } } @@ -975,9 +1089,9 @@ void Region::send_change (Change what_changed) { { - Glib::Mutex::Lock lm (lock); + Glib::Mutex::Lock lm (_lock); if (_frozen) { - pending_changed = Change (pending_changed|what_changed); + _pending_changed = Change (_pending_changed|what_changed); return; } } @@ -1017,3 +1131,135 @@ Region::region_list_equivalent (const Region& other) const { return size_equivalent (other) && source_equivalent (other) && _name == other._name; } + +void +Region::source_deleted (Source* ignored) +{ + delete this; +} + +void +Region::lock_sources () +{ + SourceList::iterator i; + set<Source*> unique_srcs; + + for (i = _sources.begin(); i != _sources.end(); ++i) { + unique_srcs.insert (*i); + (*i)->use (); + } + + for (i = _master_sources.begin(); i != _master_sources.end(); ++i) { + if (unique_srcs.find (*i) == unique_srcs.end()) { + (*i)->use (); + } + } +} + +void +Region::unlock_sources () +{ + SourceList::iterator i; + set<Source*> unique_srcs; + + for (i = _sources.begin(); i != _sources.end(); ++i) { + unique_srcs.insert (*i); + (*i)->release (); + } + + for (i = _master_sources.begin(); i != _master_sources.end(); ++i) { + if (unique_srcs.find (*i) == unique_srcs.end()) { + (*i)->release (); + } + } +} + +vector<string> +Region::master_source_names () +{ + SourceList::iterator i; + + vector<string> names; + for (i = _master_sources.begin(); i != _master_sources.end(); ++i) { + names.push_back((*i)->name()); + } + + return names; +} + +bool +Region::source_equivalent (const Region& other) const +{ + SourceList::const_iterator i; + SourceList::const_iterator io; + + for (i = _sources.begin(), io = other._sources.begin(); i != _sources.end() && io != other._sources.end(); ++i, ++io) { + if ((*i)->id() != (*io)->id()) { + return false; + } + } + + for (i = _master_sources.begin(), io = other._master_sources.begin(); i != _master_sources.end() && io != other._master_sources.end(); ++i, ++io) { + if ((*i)->id() != (*io)->id()) { + return false; + } + } + + return true; +} + +bool +Region::verify_length (jack_nframes_t len) +{ + for (uint32_t n=0; n < _sources.size(); ++n) { + if (_start > _sources[n]->length() - len) { + return false; + } + } + return true; +} + +bool +Region::verify_start_and_length (jack_nframes_t new_start, jack_nframes_t new_length) +{ + for (uint32_t n=0; n < _sources.size(); ++n) { + if (new_length > _sources[n]->length() - new_start) { + return false; + } + } + return true; +} +bool +Region::verify_start (jack_nframes_t pos) +{ + for (uint32_t n=0; n < _sources.size(); ++n) { + if (pos > _sources[n]->length() - _length) { + return false; + } + } + return true; +} + +bool +Region::verify_start_mutable (jack_nframes_t& new_start) +{ + for (uint32_t n=0; n < _sources.size(); ++n) { + if (new_start > _sources[n]->length() - _length) { + new_start = _sources[n]->length() - _length; + } + } + return true; +} + +Region* +Region::get_parent() +{ + Region* r = 0; + + if (_playlist) { + r = _playlist->session().find_whole_file_parent (*this); + } + + return r; +} + diff --git a/libs/ardour/reverse.cc b/libs/ardour/reverse.cc index 13dd531bac..b981ff0722 100644 --- a/libs/ardour/reverse.cc +++ b/libs/ardour/reverse.cc @@ -49,7 +49,6 @@ Reverse::run (AudioRegion& region) AudioRegion::SourceList::iterator si; const jack_nframes_t blocksize = 256 * 1048; Sample buf[blocksize]; - char * workbuf = 0;; jack_nframes_t fpos; jack_nframes_t fend; jack_nframes_t fstart; @@ -62,8 +61,6 @@ Reverse::run (AudioRegion& region) goto out; } - workbuf = new char[blocksize * 4]; - fend = region.start() + region.length(); fstart = region.start(); @@ -82,10 +79,11 @@ Reverse::run (AudioRegion& region) uint32_t n; for (n = 0, si = nsrcs.begin(); n < region.n_channels(); ++n, ++si) { + AudioSource* const asrc = dynamic_cast<AudioSource*>(*si); /* read it in */ - if (region.source (n).read (buf, fpos, to_read, workbuf) != to_read) { + if (region.audio_source (n).read (buf, fpos, to_read) != to_read) { goto out; } @@ -97,7 +95,7 @@ Reverse::run (AudioRegion& region) /* write it out */ - if ((*si)->write (buf, to_read, workbuf) != to_read) { + if (asrc->write (buf, to_read) != to_read) { goto out; } } @@ -123,9 +121,6 @@ Reverse::run (AudioRegion& region) delete *si; } } - if (workbuf) { - delete [] workbuf; - } return ret; } diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 58647be439..be0ec61a8d 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -37,6 +37,7 @@ #include <ardour/cycle_timer.h> #include <ardour/route_group.h> #include <ardour/port.h> +#include <ardour/audio_port.h> #include <ardour/ladspa_plugin.h> #include <ardour/panner.h> #include <ardour/dB.h> @@ -220,6 +221,9 @@ Route::process_output_buffers (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset, bool with_redirects, int declick, bool meter) { + // This is definitely very audio-only for now + assert(_default_type == DataType::AUDIO); + uint32_t n; RedirectList::iterator i; bool post_fader_work = false; @@ -650,7 +654,7 @@ Route::process_output_buffers (vector<Sample*>& bufs, uint32_t nbufs, } else { uint32_t no = n_outputs(); for (n = 0; n < no; ++n) { - _peak_power[n] = Session::compute_peak (output(n)->get_buffer (nframes) + offset, nframes, _peak_power[n]); + _peak_power[n] = Session::compute_peak (audio_output(n)->get_audio_buffer ().data(nframes, offset), nframes, _peak_power[n]); } } } @@ -663,7 +667,6 @@ Route::n_process_buffers () } void - Route::passthru (jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t nframes, jack_nframes_t offset, int declick, bool meter_first) { vector<Sample*>& bufs = _session.get_passthru_buffers(); @@ -2110,7 +2113,7 @@ Route::silent_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nfr void Route::toggle_monitor_input () { - for (vector<Port*>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { + for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { (*i)->request_monitor_input(!(*i)->monitoring_input()); } } diff --git a/libs/ardour/send.cc b/libs/ardour/send.cc index 2b72fb9bdb..fbbedf7953 100644 --- a/libs/ardour/send.cc +++ b/libs/ardour/send.cc @@ -25,6 +25,7 @@ #include <ardour/send.h> #include <ardour/session.h> #include <ardour/port.h> +#include <ardour/audio_port.h> #include "i18n.h" @@ -133,7 +134,7 @@ Send::run (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_ } else { for (n = 0; n < no; ++n) { - _peak_power[n] = Session::compute_peak (output(n)->get_buffer(nframes) + offset, nframes, _peak_power[n]); + _peak_power[n] = Session::compute_peak (audio_output(n)->get_audio_buffer().data(nframes, offset), nframes, _peak_power[n]); } } } diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index bfcb69572a..6dd6216242 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -401,10 +401,6 @@ Session::~Session () free(*i); } - for (map<RunContext,char*>::iterator i = _conversion_buffers.begin(); i != _conversion_buffers.end(); ++i) { - delete [] (i->second); - } - AudioDiskstream::free_working_buffers(); #undef TRACK_DESTRUCTION @@ -605,12 +601,7 @@ Session::when_engine_running () /* default state for Click */ - // FIXME: there's no JackPortIsAudio flag or anything like that, so this is _bad_. - // we need a get_nth_physical_audio_output or similar, but the existing one just - // deals with strings :/ - - first_physical_output = _engine.get_nth_physical_output (0); - cerr << "FIXME: click type" << endl; + first_physical_output = _engine.get_nth_physical_output (DataType::AUDIO, 0); if (first_physical_output.length()) { if (_click_io->add_output_port (first_physical_output, this)) { @@ -662,7 +653,7 @@ Session::when_engine_running () Connection* c = new OutputConnection (buf, true); c->add_port (); - c->add_connection (0, _engine.get_nth_physical_output (np)); + c->add_connection (0, _engine.get_nth_physical_output (DataType::AUDIO, np)); add_connection (c); } @@ -674,7 +665,7 @@ Session::when_engine_running () Connection* c = new InputConnection (buf, true); c->add_port (); - c->add_connection (0, _engine.get_nth_physical_input (np)); + c->add_connection (0, _engine.get_nth_physical_input (DataType::AUDIO, np)); add_connection (c); } @@ -689,8 +680,8 @@ Session::when_engine_running () c->add_port (); c->add_port (); - c->add_connection (0, _engine.get_nth_physical_output (np)); - c->add_connection (1, _engine.get_nth_physical_output (np+1)); + c->add_connection (0, _engine.get_nth_physical_output (DataType::AUDIO, np)); + c->add_connection (1, _engine.get_nth_physical_output (DataType::AUDIO, np+1)); add_connection (c); } @@ -703,8 +694,8 @@ Session::when_engine_running () c->add_port (); c->add_port (); - c->add_connection (0, _engine.get_nth_physical_input (np)); - c->add_connection (1, _engine.get_nth_physical_input (np+1)); + c->add_connection (0, _engine.get_nth_physical_input (DataType::AUDIO, np)); + c->add_connection (1, _engine.get_nth_physical_input (DataType::AUDIO, np+1)); add_connection (c); } @@ -737,7 +728,7 @@ Session::when_engine_running () } n = 0; while ((int) _master_out->n_outputs() < _master_out->output_maximum()) { - if (_master_out->add_output_port (_engine.get_nth_physical_output (n), this, DataType::AUDIO)) { + if (_master_out->add_output_port (_engine.get_nth_physical_output (DataType::AUDIO, n), this, DataType::AUDIO)) { error << _("cannot setup master outputs") << endmsg; break; @@ -828,7 +819,7 @@ Session::hookup_io () } n = 0; while ((int) _control_out->n_outputs() < _control_out->output_maximum()) { - if (_control_out->add_output_port (_engine.get_nth_physical_output (n), this)) { + if (_control_out->add_output_port (_engine.get_nth_physical_output (DataType::AUDIO, n), this)) { error << _("cannot set up master outputs") << endmsg; break; @@ -1937,7 +1928,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod port = ""; if (input_auto_connect & AutoConnectPhysical) { - port = _engine.get_nth_physical_input ((channels_used+x)%nphysical_in); + port = _engine.get_nth_physical_input (DataType::AUDIO, (channels_used+x)%nphysical_in); } if (port.length() && track->connect_input (track->input (x), port, this)) { @@ -1951,7 +1942,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod port = ""; if (nphysical_out && (output_auto_connect & AutoConnectPhysical)) { - port = _engine.get_nth_physical_output ((channels_used+x)%nphysical_out); + port = _engine.get_nth_physical_output (DataType::AUDIO, (channels_used+x)%nphysical_out); } else if (output_auto_connect & AutoConnectMaster) { if (_master_out) { port = _master_out->input (x%_master_out->n_inputs())->name(); @@ -2032,7 +2023,7 @@ Session::new_audio_route (int input_channels, int output_channels) port = ""; if (input_auto_connect & AutoConnectPhysical) { - port = _engine.get_nth_physical_input ((n+x)%n_physical_inputs); + port = _engine.get_nth_physical_input (DataType::AUDIO, (n+x)%n_physical_inputs); } if (port.length() && bus->connect_input (bus->input (x), port, this)) { @@ -2045,7 +2036,7 @@ Session::new_audio_route (int input_channels, int output_channels) port = ""; if (output_auto_connect & AutoConnectPhysical) { - port = _engine.get_nth_physical_input ((n+x)%n_physical_outputs); + port = _engine.get_nth_physical_input (DataType::AUDIO, (n+x)%n_physical_outputs); } else if (output_auto_connect & AutoConnectMaster) { if (_master_out) { port = _master_out->input (x%_master_out->n_inputs())->name(); @@ -2747,8 +2738,8 @@ Session::remove_region (Region* region) } } -AudioRegion* -Session::find_whole_file_parent (AudioRegion& child) +Region* +Session::find_whole_file_parent (Region& child) { AudioRegionList::iterator i; AudioRegion* region; @@ -3162,6 +3153,79 @@ Session::create_audio_source_for_session (AudioDiskstream& ds, uint32_t chan, bo } } +string +Session::midi_path_from_name (string name) +{ + string spath; + uint32_t cnt; + char buf[PATH_MAX+1]; + const uint32_t limit = 10000; + string legalized; + + buf[0] = '\0'; + legalized = legalize_for_path (name); + + /* find a "version" of the file name that doesn't exist in + any of the possible directories. + */ + + for (cnt = 1; cnt <= limit; ++cnt) { + + vector<space_and_path>::iterator i; + uint32_t existing = 0; + + for (i = session_dirs.begin(); i != session_dirs.end(); ++i) { + + // FIXME: different directory from audio? + spath = (*i).path + sound_dir_name + "/" + legalized; + + snprintf (buf, sizeof(buf), "%s-%u.mid", spath.c_str(), cnt); + + if (access (buf, F_OK) == 0) { + existing++; + } + } + + if (existing == 0) { + break; + } + + if (cnt > limit) { + error << string_compose(_("There are already %1 recordings for %2, which I consider too many."), limit, name) << endmsg; + throw failed_constructor(); + } + } + + /* we now have a unique name for the file, but figure out where to + actually put it. + */ + + string foo = buf; + + // FIXME: different directory than audio? + spath = discover_best_sound_dir (); + + string::size_type pos = foo.find_last_of ('/'); + + if (pos == string::npos) { + spath += foo; + } else { + spath += foo.substr (pos + 1); + } + + return spath; +} + +MidiSource * +Session::create_midi_source_for_session (MidiDiskstream& ds) +{ + string spath = midi_path_from_name (ds.name()); + + /* this might throw failed_constructor(), which is OK */ + return new SMFSource (spath); +} + + /* Playlist management */ Playlist * @@ -3789,7 +3853,7 @@ Session::freeze (InterThreadInfo& itt) int Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nframes_t len, - bool overwrite, vector<AudioSource*>& srcs, InterThreadInfo& itt) + bool overwrite, vector<Source*>& srcs, InterThreadInfo& itt) { int ret = -1; Playlist* playlist; @@ -3802,7 +3866,6 @@ Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nf jack_nframes_t this_chunk; jack_nframes_t to_do; vector<Sample*> buffers; - char * workbuf = 0; // any bigger than this seems to cause stack overflows in called functions const jack_nframes_t chunk_size = (128 * 1024)/4; @@ -3872,22 +3935,20 @@ Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nf buffers.push_back (b); } - workbuf = new char[chunk_size * 4]; - while (to_do && !itt.cancel) { this_chunk = min (to_do, chunk_size); - if (track.export_stuff (buffers, workbuf, nchans, start, this_chunk)) { + if (track.export_stuff (buffers, nchans, start, this_chunk)) { goto out; } uint32_t n = 0; - for (vector<AudioSource*>::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) { + for (vector<Source*>::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) { AudioFileSource* afs = dynamic_cast<AudioFileSource*>(*src); if (afs) { - if (afs->write (buffers[n], this_chunk, workbuf) != this_chunk) { + if (afs->write (buffers[n], this_chunk) != this_chunk) { goto out; } } @@ -3907,7 +3968,7 @@ Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nf time (&now); xnow = localtime (&now); - for (vector<AudioSource*>::iterator src=srcs.begin(); src != srcs.end(); ++src) { + for (vector<Source*>::iterator src=srcs.begin(); src != srcs.end(); ++src) { AudioFileSource* afs = dynamic_cast<AudioFileSource*>(*src); if (afs) { afs->update_header (position, *xnow, now); @@ -3916,7 +3977,7 @@ Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nf /* build peakfile for new source */ - for (vector<AudioSource*>::iterator src=srcs.begin(); src != srcs.end(); ++src) { + for (vector<Source*>::iterator src=srcs.begin(); src != srcs.end(); ++src) { AudioFileSource* afs = dynamic_cast<AudioFileSource*>(*src); if (afs) { afs->build_peaks (); @@ -3928,7 +3989,7 @@ Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nf out: if (ret) { - for (vector<AudioSource*>::iterator src=srcs.begin(); src != srcs.end(); ++src) { + for (vector<Source*>::iterator src=srcs.begin(); src != srcs.end(); ++src) { AudioFileSource* afs = dynamic_cast<AudioFileSource*>(*src); if (afs) { afs->mark_for_remove (); @@ -3941,10 +4002,6 @@ Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nf free(*i); } - if (workbuf) { - delete [] workbuf; - } - g_atomic_int_set (&processing_prohibited, 0); itt.done = true; diff --git a/libs/ardour/session_command.cc b/libs/ardour/session_command.cc index 9a43de55de..1b8d6b3718 100644 --- a/libs/ardour/session_command.cc +++ b/libs/ardour/session_command.cc @@ -1,7 +1,29 @@ #include <ardour/session.h> #include <ardour/route.h> +#include <pbd/memento_command.h> +#include <ardour/diskstream.h> namespace ARDOUR { + +Command *Session::memento_command_factory(XMLNode *n) +{ + PBD::ID id; + XMLNode *before, *after; + //void *obj; + + /* get obj_id */ + + /* get before and/or after */ + + /* get an object by id by trial and error, and use it to construct an + * appropriate memento command */ + // e.g. + if (Diskstream *obj = diskstream_by_id(id)) + return new MementoCommand<Diskstream>(*obj, *before, *after); + // etc. + return 0; +} + // solo Session::GlobalSoloStateCommand::GlobalSoloStateCommand(Session &sess, void *src) : sess(sess), src(src) diff --git a/libs/ardour/session_export.cc b/libs/ardour/session_export.cc index b39c4f2218..c5449d3e06 100644 --- a/libs/ardour/session_export.cc +++ b/libs/ardour/session_export.cc @@ -46,6 +46,7 @@ #include <ardour/export.h> #include <ardour/sndfile_helpers.h> #include <ardour/port.h> +#include <ardour/audio_port.h> #include <ardour/audioengine.h> #include <ardour/audio_diskstream.h> #include <ardour/panner.h> @@ -604,8 +605,12 @@ Session::process_export (jack_nframes_t nframes, AudioExportSpecification* spec) /* OK, this port's output is supposed to appear on this channel */ - Port* port = (*t).first; - Sample* port_buffer = port->get_buffer (nframes); + AudioPort* const port = dynamic_cast<AudioPort*>((*t).first); + if (port == 0) { + cerr << "FIXME: Non-audio export" << endl; + continue; + } + Sample* port_buffer = port->get_audio_buffer().data(nframes); /* now interleave the data from the channel into the float buffer */ diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index bb319511b7..a235375ed1 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -194,9 +194,6 @@ Session::first_stage_init (string fullpath, string snapshot_name) xfade_model = ShortCrossfade; destructive_index = 0; - /* allocate conversion buffers */ - _conversion_buffers[ButlerContext] = new char[AudioDiskstream::disk_io_frames() * 4]; - _conversion_buffers[TransportContext] = new char[AudioDiskstream::disk_io_frames() * 4]; AudioDiskstream::allocate_working_buffers(); /* default short fade = 15ms */ @@ -628,15 +625,16 @@ Session::load_diskstreams (const XMLNode& node) clist = node.children(); for (citer = clist.begin(); citer != clist.end(); ++citer) { - Diskstream* dstream = NULL; + Diskstream* dstream = 0; try { - if ((*citer)->name() == "AudioDiskstream") { + /* diskstreams added automatically by DiskstreamCreated handler */ + if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") { dstream = new AudioDiskstream (*this, **citer); - /* added automatically by DiskstreamCreated handler */ - } else { - assert((*citer)->name() == "MidiDiskstream"); + } else if ((*citer)->name() == "MidiDiskstream") { dstream = new MidiDiskstream (*this, **citer); + } else { + error << _("Session: unknown diskstream type in XML") << endmsg; } } diff --git a/libs/ardour/session_timefx.cc b/libs/ardour/session_timefx.cc index 7eec1e578b..82fd25ddb2 100644 --- a/libs/ardour/session_timefx.cc +++ b/libs/ardour/session_timefx.cc @@ -96,10 +96,15 @@ Session::tempoize_region (TimeStretchRequest& tsr) for (uint32_t i = 0; i < sources.size(); ++i) { gain_t gain_buffer[bufsize]; Sample buffer[bufsize]; - char workbuf[bufsize*4]; jack_nframes_t pos = 0; jack_nframes_t this_read = 0; + AudioSource* const asrc = dynamic_cast<AudioSource*>(sources[i]); + if (!asrc) { + cerr << "FIXME: TimeFX for non-audio" << endl; + continue; + } + st.clear(); while (tsr.running && pos < tsr.region->length()) { jack_nframes_t this_time; @@ -110,7 +115,7 @@ Session::tempoize_region (TimeStretchRequest& tsr) not the ones currently in use, in case it's already been subject to timefx. */ - if ((this_read = tsr.region->master_read_at (buffer, buffer, gain_buffer, workbuf, pos + tsr.region->position(), this_time)) != this_time) { + if ((this_read = tsr.region->master_read_at (buffer, buffer, gain_buffer, pos + tsr.region->position(), this_time)) != this_time) { error << string_compose (_("tempoize: error reading data from %1"), sources[i]->name()) << endmsg; goto out; } @@ -123,7 +128,7 @@ Session::tempoize_region (TimeStretchRequest& tsr) st.putSamples (buffer, this_read); while ((this_read = st.receiveSamples (buffer, bufsize)) > 0 && tsr.running) { - if (sources[i]->write (buffer, this_read, workbuf) != this_read) { + if (asrc->write (buffer, this_read) != this_read) { error << string_compose (_("error writing tempo-adjusted data to %1"), sources[i]->name()) << endmsg; goto out; } @@ -135,7 +140,7 @@ Session::tempoize_region (TimeStretchRequest& tsr) } while (tsr.running && (this_read = st.receiveSamples (buffer, bufsize)) > 0) { - if (sources[i]->write (buffer, this_read, workbuf) != this_read) { + if (asrc->write (buffer, this_read) != this_read) { error << string_compose (_("error writing tempo-adjusted data to %1"), sources[i]->name()) << endmsg; goto out; } diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc index 10cf7ab335..86e2e8a9aa 100644 --- a/libs/ardour/smf_source.cc +++ b/libs/ardour/smf_source.cc @@ -103,6 +103,29 @@ SMFSource::init (string pathstr, bool must_exist) return 0; } +int +SMFSource::update_header (jack_nframes_t when, struct tm&, time_t) +{ + return 0; +} + +int +SMFSource::flush_header () +{ + return 0; +} + +jack_nframes_t +SMFSource::read_unlocked (RawMidi* dst, jack_nframes_t start, jack_nframes_t cnt) const +{ + return 0; +} + +jack_nframes_t +SMFSource::write_unlocked (RawMidi* dst, jack_nframes_t cnt) +{ + return 0; +} XMLNode& SMFSource::get_state () diff --git a/libs/ardour/sndfilesource.cc b/libs/ardour/sndfilesource.cc index 5936f62570..b487d4e3a3 100644 --- a/libs/ardour/sndfilesource.cc +++ b/libs/ardour/sndfilesource.cc @@ -292,7 +292,7 @@ SndFileSource::sample_rate () const } jack_nframes_t -SndFileSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const +SndFileSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const { int32_t nread; float *ptr; @@ -367,7 +367,7 @@ SndFileSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t } jack_nframes_t -SndFileSource::write_unlocked (Sample *data, jack_nframes_t cnt, char * workbuf) +SndFileSource::write_unlocked (Sample *data, jack_nframes_t cnt) { if (!writable()) { return 0; diff --git a/libs/ardour/source.cc b/libs/ardour/source.cc index eebc64d463..e5aba19d2c 100644 --- a/libs/ardour/source.cc +++ b/libs/ardour/source.cc @@ -117,3 +117,11 @@ Source::release () if (_use_cnt) --_use_cnt; } +void +Source::update_length (jack_nframes_t pos, jack_nframes_t cnt) +{ + if (pos + cnt > _length) { + _length = pos+cnt; + } +} + diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc index f81ef9de4d..49578a7d04 100644 --- a/libs/ardour/track.cc +++ b/libs/ardour/track.cc @@ -88,7 +88,7 @@ Track::get_template () void Track::toggle_monitor_input () { - for (vector<Port*>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { + for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { (*i)->request_monitor_input(!(*i)->monitoring_input()); } } @@ -152,8 +152,8 @@ bool Track::can_record() { bool will_record = true; - for (size_t i = 0; i < _inputs.size() && will_record; i++) { - if (!_inputs[i]->connected()) + for (PortSet::iterator i = _inputs.begin(); i != _inputs.end() && will_record; ++i) { + if (!(*i)->connected()) will_record = false; } |