diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2007-03-16 17:48:13 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2007-03-16 17:48:13 +0000 |
commit | 3e369073533988b8536216389d52cc947535e51c (patch) | |
tree | e5b0cdbc7540df68222f76574cf84fa48d3e70f7 | |
parent | bca0450c188cdac82fbc74d05b5d72aff9115646 (diff) |
a much better fix for track-add crashes, albeit slightly more complex
git-svn-id: svn://localhost/ardour2/trunk@1604 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r-- | libs/ardour/ardour/audio_diskstream.h | 61 | ||||
-rw-r--r-- | libs/ardour/ardour/diskstream.h | 4 | ||||
-rw-r--r-- | libs/ardour/ardour/session.h | 4 | ||||
-rw-r--r-- | libs/ardour/audio_diskstream.cc | 524 | ||||
-rw-r--r-- | libs/ardour/auditioner.cc | 12 | ||||
-rw-r--r-- | libs/ardour/diskstream.cc | 2 | ||||
-rw-r--r-- | libs/ardour/session.cc | 10 | ||||
-rw-r--r-- | libs/ardour/session_events.cc | 12 | ||||
-rw-r--r-- | libs/ardour/session_transport.cc | 25 |
9 files changed, 317 insertions, 337 deletions
diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h index cb70903d13..4846a20cbd 100644 --- a/libs/ardour/ardour/audio_diskstream.h +++ b/libs/ardour/ardour/audio_diskstream.h @@ -32,6 +32,7 @@ #include <pbd/fastlog.h> #include <pbd/ringbufferNPT.h> #include <pbd/stateful.h> +#include <pbd/rcu.h> #include <ardour/ardour.h> #include <ardour/configuration.h> @@ -65,24 +66,28 @@ class AudioDiskstream : public Diskstream float capture_buffer_load() const; string input_source (uint32_t n=0) const { - if (n < channels.size()) { - return channels[n].source ? channels[n].source->name() : ""; + boost::shared_ptr<ChannelList> c = channels.reader(); + if (n < c->size()) { + return (*c)[n]->source ? (*c)[n]->source->name() : ""; } else { return ""; } } Port *input_source_port (uint32_t n=0) const { - if (n < channels.size()) return channels[n].source; return 0; + boost::shared_ptr<ChannelList> c = channels.reader(); + if (n < c->size()) return (*c)[n]->source; return 0; } void set_record_enabled (bool yn); int set_destructive (bool yn); bool can_become_destructive (bool& requires_bounce) const; - float peak_power(uint32_t n=0) { - float x = channels[n].peak_power; - channels[n].peak_power = 0.0f; + float peak_power(uint32_t n = 0) { + boost::shared_ptr<ChannelList> c = channels.reader(); + ChannelInfo* chaninfo = (*c)[n]; + float x = chaninfo->peak_power; + chaninfo->peak_power = 0.0f; if (x > 0.0f) { return 20.0f * fast_log10(x); } else { @@ -96,27 +101,29 @@ class AudioDiskstream : public Diskstream int use_new_playlist (); int use_copy_playlist (); - Sample *playback_buffer (uint32_t n=0) { - if (n < channels.size()) - return channels[n].current_playback_buffer; + Sample *playback_buffer (uint32_t n = 0) { + boost::shared_ptr<ChannelList> c = channels.reader(); + if (n < c->size()) + return (*c)[n]->current_playback_buffer; return 0; } - Sample *capture_buffer (uint32_t n=0) { - if (n < channels.size()) - return channels[n].current_capture_buffer; + Sample *capture_buffer (uint32_t n = 0) { + boost::shared_ptr<ChannelList> c = channels.reader(); + if (n < c->size()) + return (*c)[n]->current_capture_buffer; return 0; } boost::shared_ptr<AudioFileSource> write_source (uint32_t n=0) { - if (n < channels.size()) - return channels[n].write_source; + boost::shared_ptr<ChannelList> c = channels.reader(); + if (n < c->size()) + return (*c)[n]->write_source; return boost::shared_ptr<AudioFileSource>(); } - int add_channel (); - int remove_channel (); - + int add_channel (uint32_t how_many); + int remove_channel (uint32_t how_many); /* stateful */ @@ -174,12 +181,9 @@ class AudioDiskstream : public Diskstream struct ChannelInfo { - ChannelInfo (); + ChannelInfo (nframes_t buffer_size, nframes_t speed_buffer_size, nframes_t wrap_buffer_size); ~ChannelInfo (); - void init (nframes_t buffer_size, nframes_t speed_buffer_size, nframes_t wrap_buffer_size); - void release (); - Sample *playback_wrap_buffer; Sample *capture_wrap_buffer; Sample *speed_buffer; @@ -208,6 +212,8 @@ class AudioDiskstream : public Diskstream nframes_t curr_capture_cnt; }; + typedef std::vector<ChannelInfo*> ChannelList; + /* The two central butler operations */ int do_flush (Session::RunContext context, bool force = false); int do_refill () { return _do_refill(_mixdown_buffer, _gain_buffer); } @@ -215,10 +221,10 @@ class AudioDiskstream : public Diskstream int do_refill_with_alloc (); int read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, - nframes_t& start, nframes_t cnt, - ChannelInfo& channel_info, int channel, bool reversed); + nframes_t& start, nframes_t cnt, + ChannelInfo* channel_info, int channel, bool reversed); - void finish_capture (bool rec_monitors_input); + void finish_capture (bool rec_monitors_input, boost::shared_ptr<ChannelList>); void transport_stopped (struct tm&, time_t, bool abort); void init (Diskstream::Flag); @@ -253,12 +259,15 @@ class AudioDiskstream : public Diskstream std::vector<boost::shared_ptr<AudioFileSource> > capturing_sources; - typedef vector<ChannelInfo> ChannelList; - ChannelList channels; + SerializedRCUManager<ChannelList> channels; /* really */ private: int _do_refill (Sample *mixdown_buffer, float *gain_buffer); + + int add_channel_to (boost::shared_ptr<ChannelList>, uint32_t how_many); + int remove_channel_from (boost::shared_ptr<ChannelList>, uint32_t how_many); + }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h index a03b778dd9..c6371f180d 100644 --- a/libs/ardour/ardour/diskstream.h +++ b/libs/ardour/ardour/diskstream.h @@ -21,7 +21,6 @@ #define __ardour_diskstream_h__ #include <sigc++/signal.h> -#include <boost/enable_shared_from_this.hpp> #include <cmath> #include <string> @@ -54,7 +53,7 @@ class Session; class Playlist; class IO; -class Diskstream : public PBD::StatefulDestructible, public boost::enable_shared_from_this<ARDOUR::Diskstream> +class Diskstream : public PBD::StatefulDestructible { public: enum Flag { @@ -207,7 +206,6 @@ class Diskstream : public PBD::StatefulDestructible, public boost::enable_shared virtual void playlist_modified (); virtual void playlist_deleted (boost::weak_ptr<Playlist>); - virtual void finish_capture (bool rec_monitors_input) = 0; virtual void transport_stopped (struct tm&, time_t, bool abort) = 0; struct CaptureInfo { diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 9955dd9311..919d9a8162 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -165,7 +165,6 @@ class Session : public PBD::StatefulDestructible }; boost::shared_ptr<Region> region; - boost::shared_ptr<Diskstream> diskstream; list<AudioRange> audio_range; list<MusicRange> music_range; @@ -362,7 +361,7 @@ class Session : public PBD::StatefulDestructible void request_transport_speed (float speed); void request_overwrite_buffer (Diskstream*); void request_diskstream_speed (Diskstream&, float speed); - void request_input_change_handling (boost::shared_ptr<ARDOUR::Diskstream>); + void request_input_change_handling (); bool locate_pending() const { return static_cast<bool>(post_transport_work&PostTransportLocate); } bool transport_locked () const; @@ -1425,7 +1424,6 @@ class Session : public PBD::StatefulDestructible /* disk-streams */ SerializedRCUManager<DiskstreamList> diskstreams; - SerializedRCUManager<DiskstreamList> diskstreams_input_pending; uint32_t dstream_buffer_size; int load_diskstreams (const XMLNode&); diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index e72519ef7d..887838796b 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -66,6 +66,7 @@ gain_t* AudioDiskstream::_gain_buffer = 0; AudioDiskstream::AudioDiskstream (Session &sess, const string &name, Diskstream::Flag flag) : Diskstream(sess, name, flag) , deprecated_io_node(NULL) + , channels (new ChannelList) { /* prevent any write sources from being created */ @@ -80,6 +81,7 @@ AudioDiskstream::AudioDiskstream (Session &sess, const string &name, Diskstream: AudioDiskstream::AudioDiskstream (Session& sess, const XMLNode& node) : Diskstream(sess, node) , deprecated_io_node(NULL) + , channels (new ChannelList) { in_set_state = true; init (Recordable); @@ -109,7 +111,7 @@ AudioDiskstream::init (Diskstream::Flag f) set_block_size (_session.get_block_size()); allocate_temporary_buffers (); - add_channel (); + add_channel (1); assert(_n_channels == 1); } @@ -118,16 +120,17 @@ AudioDiskstream::~AudioDiskstream () notify_callbacks (); { - /* don't be holding this lock as we exit the destructor, glib will wince - visibly since the mutex gets destroyed before we release it. - */ - - Glib::Mutex::Lock lm (state_lock); - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { - (*chan).release (); + RCUWriter<ChannelList> writer (channels); + boost::shared_ptr<ChannelList> c = writer.get_copy(); + + for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { + delete *chan; } - channels.clear(); + + c->clear(); } + + channels.flush (); } void @@ -153,37 +156,26 @@ AudioDiskstream::free_working_buffers() void AudioDiskstream::non_realtime_input_change () { - { + { Glib::Mutex::Lock lm (state_lock); if (input_change_pending == NoChange) { return; } - if (input_change_pending & ConfigurationChanged) { - + { + RCUWriter<ChannelList> writer (channels); + boost::shared_ptr<ChannelList> c = writer.get_copy(); + + _n_channels = c->size(); + if (_io->n_inputs() > _n_channels) { - - // we need to add new channel infos - - int diff = _io->n_inputs() - channels.size(); - - for (int i = 0; i < diff; ++i) { - add_channel (); - } - - } else if (_io->n_inputs() < _n_channels) { - - // we need to get rid of channels - - int diff = channels.size() - _io->n_inputs(); - - for (int i = 0; i < diff; ++i) { - remove_channel (); - } + add_channel_to (c, _io->n_inputs() - _n_channels); + } else if (_io->n_inputs() < _n_channels) { + remove_channel_from (c, _n_channels - _io->n_inputs()); } - } - + } + get_input_sources (); set_capture_offset (); @@ -193,10 +185,12 @@ AudioDiskstream::non_realtime_input_change () } else { set_align_style_from_io (); } - + input_change_pending = NoChange; - } + /* implicit unlock */ + } + /* reset capture files */ reset_write_sources (false); @@ -213,23 +207,26 @@ AudioDiskstream::non_realtime_input_change () void AudioDiskstream::get_input_sources () { + boost::shared_ptr<ChannelList> c = channels.reader(); + + uint32_t n; + ChannelList::iterator chan; uint32_t ni = _io->n_inputs(); - - for (uint32_t n = 0; n < ni; ++n) { + + for (n = 0, chan = c->begin(); chan != c->end() && n < ni; ++chan, ++n) { const char **connections = _io->input(n)->get_connections (); - ChannelInfo& chan = channels[n]; if (connections == 0 || connections[0] == 0) { - if (chan.source) { + if ((*chan)->source) { // _source->disable_metering (); } - chan.source = 0; + (*chan)->source = 0; } else { - chan.source = _session.engine().get_port_by_name (connections[0]); + (*chan)->source = _session.engine().get_port_by_name (connections[0]); } if (connections) { @@ -322,9 +319,10 @@ void AudioDiskstream::setup_destructive_playlist () { SourceList srcs; - - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { - srcs.push_back ((*chan).write_source); + boost::shared_ptr<ChannelList> c = channels.reader(); + + for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { + srcs.push_back ((*chan)->write_source); } /* a single full-sized region */ @@ -361,15 +359,16 @@ AudioDiskstream::use_destructive_playlist () uint32_t n; ChannelList::iterator chan; + boost::shared_ptr<ChannelList> c = channels.reader(); - for (n = 0, chan = channels.begin(); chan != channels.end(); ++chan, ++n) { - (*chan).write_source = boost::dynamic_pointer_cast<AudioFileSource>(region->source (n)); - assert((*chan).write_source); - (*chan).write_source->set_allow_remove_if_empty (false); + for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) { + (*chan)->write_source = boost::dynamic_pointer_cast<AudioFileSource>(region->source (n)); + assert((*chan)->write_source); + (*chan)->write_source->set_allow_remove_if_empty (false); /* this might be false if we switched modes, so force it */ - (*chan).write_source->set_destructive (true); + (*chan)->write_source->set_destructive (true); } /* the source list will never be reset for a destructive track */ @@ -465,15 +464,16 @@ AudioDiskstream::check_record_status (nframes_t transport_frame, nframes_t nfram } if (_flags & Recordable) { - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { + boost::shared_ptr<ChannelList> c = channels.reader(); + for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { RingBufferNPT<CaptureTransition>::rw_vector transvec; - (*chan).capture_transition_buf->get_write_vector(&transvec); + (*chan)->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; - (*chan).capture_transition_buf->increment_write_ptr(1); + (*chan)->capture_transition_buf->increment_write_ptr(1); } else { // bad! @@ -503,7 +503,8 @@ int AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_t offset, bool can_record, bool rec_monitors_input) { uint32_t n; - ChannelList::iterator c; + boost::shared_ptr<ChannelList> c = channels.reader(); + ChannelList::iterator chan; int ret = -1; nframes_t rec_offset = 0; nframes_t rec_nframes = 0; @@ -544,9 +545,9 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_ adjust_capture_position = 0; - for (c = channels.begin(); c != channels.end(); ++c) { - (*c).current_capture_buffer = 0; - (*c).current_playback_buffer = 0; + for (chan = c->begin(); chan != c->end(); ++chan) { + (*chan)->current_capture_buffer = 0; + (*chan)->current_playback_buffer = 0; } if (nominally_recording || (_session.get_record_enabled() && Config->get_punch_in())) { @@ -607,25 +608,25 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_ if (nominally_recording || rec_nframes) { - for (n = 0, c = channels.begin(); c != channels.end(); ++c, ++n) { + for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) { - ChannelInfo& chan (*c); - - chan.capture_buf->get_write_vector (&chan.capture_vector); + ChannelInfo* chaninfo (*chan); - if (rec_nframes <= chan.capture_vector.len[0]) { + chaninfo->capture_buf->get_write_vector (&chaninfo->capture_vector); + + if (rec_nframes <= chaninfo->capture_vector.len[0]) { - chan.current_capture_buffer = chan.capture_vector.buf[0]; + chaninfo->current_capture_buffer = chaninfo->capture_vector.buf[0]; /* note: grab the entire port buffer, but only copy what we were supposed to for recording, and use rec_offset */ - memcpy (chan.current_capture_buffer, _io->input(n)->get_buffer (rec_nframes) + offset + rec_offset, sizeof (Sample) * rec_nframes); + memcpy (chaninfo->current_capture_buffer, _io->input(n)->get_buffer (rec_nframes) + offset + rec_offset, sizeof (Sample) * rec_nframes); } else { - nframes_t total = chan.capture_vector.len[0] + chan.capture_vector.len[1]; + nframes_t total = chaninfo->capture_vector.len[0] + chaninfo->capture_vector.len[1]; if (rec_nframes > total) { DiskOverrun (); @@ -633,21 +634,21 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_ } Sample* buf = _io->input (n)->get_buffer (nframes) + offset; - nframes_t first = chan.capture_vector.len[0]; + nframes_t first = chaninfo->capture_vector.len[0]; - memcpy (chan.capture_wrap_buffer, buf, sizeof (Sample) * first); - memcpy (chan.capture_vector.buf[0], buf, sizeof (Sample) * first); - memcpy (chan.capture_wrap_buffer+first, buf + first, sizeof (Sample) * (rec_nframes - first)); - memcpy (chan.capture_vector.buf[1], buf + first, sizeof (Sample) * (rec_nframes - first)); + memcpy (chaninfo->capture_wrap_buffer, buf, sizeof (Sample) * first); + memcpy (chaninfo->capture_vector.buf[0], buf, sizeof (Sample) * first); + memcpy (chaninfo->capture_wrap_buffer+first, buf + first, sizeof (Sample) * (rec_nframes - first)); + memcpy (chaninfo->capture_vector.buf[1], buf + first, sizeof (Sample) * (rec_nframes - first)); - chan.current_capture_buffer = chan.capture_wrap_buffer; + chaninfo->current_capture_buffer = chaninfo->capture_wrap_buffer; } } } else { if (was_recording) { - finish_capture (rec_monitors_input); + finish_capture (rec_monitors_input, c); } } @@ -658,8 +659,8 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_ if (rec_nframes == nframes && rec_offset == 0) { - for (c = channels.begin(); c != channels.end(); ++c) { - (*c).current_playback_buffer = (*c).current_capture_buffer; + for (chan = c->begin(); chan != c->end(); ++chan) { + (*chan)->current_playback_buffer = (*chan)->current_capture_buffer; } playback_distance = nframes; @@ -681,8 +682,8 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_ /* can't do actual capture yet - waiting for latency effects to finish before we start*/ - for (c = channels.begin(); c != channels.end(); ++c) { - (*c).current_playback_buffer = (*c).current_capture_buffer; + for (chan = c->begin(); chan != c->end(); ++chan) { + (*chan)->current_playback_buffer = (*chan)->current_capture_buffer; } playback_distance = nframes; @@ -706,22 +707,22 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_ necessary_samples = nframes; } - for (c = channels.begin(); c != channels.end(); ++c) { - (*c).playback_buf->get_read_vector (&(*c).playback_vector); + for (chan = c->begin(); chan != c->end(); ++chan) { + (*chan)->playback_buf->get_read_vector (&(*chan)->playback_vector); } n = 0; - for (c = channels.begin(); c != channels.end(); ++c, ++n) { - - ChannelInfo& chan (*c); + for (chan = c->begin(); chan != c->end(); ++chan, ++n) { + + ChannelInfo* chaninfo (*chan); - if (necessary_samples <= chan.playback_vector.len[0]) { + if (necessary_samples <= chaninfo->playback_vector.len[0]) { - chan.current_playback_buffer = chan.playback_vector.buf[0]; + chaninfo->current_playback_buffer = chaninfo->playback_vector.buf[0]; } else { - nframes_t total = chan.playback_vector.len[0] + chan.playback_vector.len[1]; + nframes_t total = chaninfo->playback_vector.len[0] + chaninfo->playback_vector.len[1]; if (necessary_samples > total) { DiskUnderrun (); @@ -729,12 +730,12 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_ } else { - memcpy ((char *) chan.playback_wrap_buffer, chan.playback_vector.buf[0], - chan.playback_vector.len[0] * sizeof (Sample)); - memcpy (chan.playback_wrap_buffer + chan.playback_vector.len[0], chan.playback_vector.buf[1], - (necessary_samples - chan.playback_vector.len[0]) * sizeof (Sample)); + memcpy ((char *) chaninfo->playback_wrap_buffer, chaninfo->playback_vector.buf[0], + chaninfo->playback_vector.len[0] * sizeof (Sample)); + memcpy (chaninfo->playback_wrap_buffer + chaninfo->playback_vector.len[0], chaninfo->playback_vector.buf[1], + (necessary_samples - chaninfo->playback_vector.len[0]) * sizeof (Sample)); - chan.current_playback_buffer = chan.playback_wrap_buffer; + chaninfo->current_playback_buffer = chaninfo->playback_wrap_buffer; } } } @@ -747,10 +748,10 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_ // Linearly interpolate into the alt buffer // using 40.24 fixp maths (swh) - for (c = channels.begin(); c != channels.end(); ++c) { + for (chan = c->begin(); chan != c->end(); ++chan) { float fr; - ChannelInfo& chan (*c); + ChannelInfo* chaninfo (*chan); i = 0; phase = last_phase; @@ -758,13 +759,13 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_ for (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; + chaninfo->speed_buffer[outsample] = + chaninfo->current_playback_buffer[i] * (1.0f - fr) + + chaninfo->current_playback_buffer[i+1] * fr; phase += phi; } - chan.current_playback_buffer = chan.speed_buffer; + chaninfo->current_playback_buffer = chaninfo->speed_buffer; } playback_distance = i + 1; @@ -804,12 +805,13 @@ AudioDiskstream::commit (nframes_t nframes) playback_sample += playback_distance; } - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { + boost::shared_ptr<ChannelList> c = channels.reader(); + for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { - (*chan).playback_buf->increment_read_ptr (playback_distance); + (*chan)->playback_buf->increment_read_ptr (playback_distance); if (adjust_capture_position) { - (*chan).capture_buf->increment_write_ptr (adjust_capture_position); + (*chan)->capture_buf->increment_write_ptr (adjust_capture_position); } } @@ -819,10 +821,10 @@ AudioDiskstream::commit (nframes_t nframes) } if (_slaved) { - need_butler = channels[0].playback_buf->write_space() >= channels[0].playback_buf->bufsize() / 2; + need_butler = c->front()->playback_buf->write_space() >= c->front()->playback_buf->bufsize() / 2; } else { - need_butler = channels[0].playback_buf->write_space() >= disk_io_chunk_frames - || channels[0].capture_buf->read_space() >= disk_io_chunk_frames; + need_butler = c->front()->playback_buf->write_space() >= disk_io_chunk_frames + || c->front()->capture_buf->read_space() >= disk_io_chunk_frames; } state_lock.unlock(); @@ -839,12 +841,13 @@ AudioDiskstream::set_pending_overwrite (bool yn) pending_overwrite = yn; overwrite_frame = playback_sample; - overwrite_offset = channels.front().playback_buf->get_read_ptr(); + overwrite_offset = channels.reader()->front()->playback_buf->get_read_ptr(); } int AudioDiskstream::overwrite_existing_buffers () { + boost::shared_ptr<ChannelList> c = channels.reader(); Sample* mixdown_buffer; float* gain_buffer; int ret = -1; @@ -853,7 +856,7 @@ AudioDiskstream::overwrite_existing_buffers () overwrite_queued = false; /* assume all are the same size */ - nframes_t size = channels[0].playback_buf->bufsize(); + nframes_t size = c->front()->playback_buf->bufsize(); mixdown_buffer = new Sample[size]; gain_buffer = new float[size]; @@ -864,7 +867,7 @@ AudioDiskstream::overwrite_existing_buffers () uint32_t n=0; nframes_t start; - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan, ++n) { + for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan, ++n) { start = overwrite_frame; nframes_t cnt = size; @@ -882,7 +885,7 @@ AudioDiskstream::overwrite_existing_buffers () nframes_t to_read = size - overwrite_offset; - if (read ((*chan).playback_buf->buffer() + overwrite_offset, mixdown_buffer, gain_buffer, 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; @@ -892,7 +895,7 @@ AudioDiskstream::overwrite_existing_buffers () cnt -= to_read; - if (read ((*chan).playback_buf->buffer(), mixdown_buffer, gain_buffer, + 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; @@ -916,11 +919,13 @@ AudioDiskstream::seek (nframes_t frame, bool complete_refill) uint32_t n; int ret; ChannelList::iterator chan; + boost::shared_ptr<ChannelList> c = channels.reader(); + Glib::Mutex::Lock lm (state_lock); - for (n = 0, chan = channels.begin(); chan != channels.end(); ++chan, ++n) { - (*chan).playback_buf->reset (); - (*chan).capture_buf->reset (); + for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) { + (*chan)->playback_buf->reset (); + (*chan)->capture_buf->reset (); } /* can't rec-enable in destructive mode if transport is before start */ @@ -945,9 +950,10 @@ int AudioDiskstream::can_internal_playback_seek (nframes_t distance) { ChannelList::iterator chan; + boost::shared_ptr<ChannelList> c = channels.reader(); - for (chan = channels.begin(); chan != channels.end(); ++chan) { - if ((*chan).playback_buf->read_space() < distance) { + for (chan = c->begin(); chan != c->end(); ++chan) { + if ((*chan)->playback_buf->read_space() < distance) { return false; } } @@ -958,9 +964,10 @@ int AudioDiskstream::internal_playback_seek (nframes_t distance) { ChannelList::iterator chan; + boost::shared_ptr<ChannelList> c = channels.reader(); - for (chan = channels.begin(); chan != channels.end(); ++chan) { - (*chan).playback_buf->increment_read_ptr (distance); + for (chan = c->begin(); chan != c->end(); ++chan) { + (*chan)->playback_buf->increment_read_ptr (distance); } first_recordable_frame += distance; @@ -971,7 +978,7 @@ AudioDiskstream::internal_playback_seek (nframes_t distance) int AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, nframes_t& start, nframes_t cnt, - ChannelInfo& channel_info, int channel, bool reversed) + ChannelInfo* channel_info, int channel, bool reversed) { nframes_t this_read = 0; bool reloop = false; @@ -1090,8 +1097,13 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer) nframes_t zero_fill; uint32_t chan_n; ChannelList::iterator i; + boost::shared_ptr<ChannelList> c = channels.reader(); nframes_t ts; + if (c->empty()) { + return 0; + } + assert(mixdown_buffer); assert(gain_buffer); @@ -1100,7 +1112,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer) vector.buf[1] = 0; vector.len[1] = 0; - channels.front().playback_buf->get_write_vector (&vector); + c->front()->playback_buf->get_write_vector (&vector); if ((total_space = vector.len[0] + vector.len[1]) == 0) { return 0; @@ -1131,7 +1143,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer) work with. */ - if (_slaved && total_space < (channels.front().playback_buf->bufsize() / 2)) { + if (_slaved && total_space < (c->front()->playback_buf->bufsize() / 2)) { return 0; } @@ -1145,15 +1157,15 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer) /* at start: nothing to do but fill with silence */ - for (chan_n = 0, i = channels.begin(); i != channels.end(); ++i, ++chan_n) { + for (chan_n = 0, i = c->begin(); i != c->end(); ++i, ++chan_n) { - ChannelInfo& chan (*i); - chan.playback_buf->get_write_vector (&vector); + ChannelInfo* chan (*i); + chan->playback_buf->get_write_vector (&vector); memset (vector.buf[0], 0, sizeof(Sample) * vector.len[0]); if (vector.len[1]) { memset (vector.buf[1], 0, sizeof(Sample) * vector.len[1]); } - chan.playback_buf->increment_write_ptr (vector.len[0] + vector.len[1]); + chan->playback_buf->increment_write_ptr (vector.len[0] + vector.len[1]); } return 0; } @@ -1179,15 +1191,15 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer) /* at end: nothing to do but fill with silence */ - for (chan_n = 0, i = channels.begin(); i != channels.end(); ++i, ++chan_n) { + for (chan_n = 0, i = c->begin(); i != c->end(); ++i, ++chan_n) { - ChannelInfo& chan (*i); - chan.playback_buf->get_write_vector (&vector); + ChannelInfo* chan (*i); + chan->playback_buf->get_write_vector (&vector); memset (vector.buf[0], 0, sizeof(Sample) * vector.len[0]); if (vector.len[1]) { memset (vector.buf[1], 0, sizeof(Sample) * vector.len[1]); } - chan.playback_buf->increment_write_ptr (vector.len[0] + vector.len[1]); + chan->playback_buf->increment_write_ptr (vector.len[0] + vector.len[1]); } return 0; } @@ -1206,14 +1218,14 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer) nframes_t file_frame_tmp = 0; - for (chan_n = 0, i = channels.begin(); i != channels.end(); ++i, ++chan_n) { + for (chan_n = 0, i = c->begin(); i != c->end(); ++i, ++chan_n) { - ChannelInfo& chan (*i); + ChannelInfo* chan (*i); Sample* buf1; Sample* buf2; nframes_t len1, len2; - chan.playback_buf->get_write_vector (&vector); + chan->playback_buf->get_write_vector (&vector); if (vector.len[0] > disk_io_chunk_frames) { @@ -1256,7 +1268,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer) goto out; } - chan.playback_buf->increment_write_ptr (to_read); + chan->playback_buf->increment_write_ptr (to_read); ts -= to_read; } @@ -1273,7 +1285,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer) goto out; } - chan.playback_buf->increment_write_ptr (to_read); + chan->playback_buf->increment_write_ptr (to_read); } if (zero_fill) { @@ -1315,9 +1327,10 @@ AudioDiskstream::do_flush (Session::RunContext context, bool force_flush) vector.buf[0] = 0; vector.buf[1] = 0; - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { + boost::shared_ptr<ChannelList> c = channels.reader(); + for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { - (*chan).capture_buf->get_read_vector (&vector); + (*chan)->capture_buf->get_read_vector (&vector); total = vector.len[0] + vector.len[1]; @@ -1346,7 +1359,7 @@ AudioDiskstream::do_flush (Session::RunContext context, bool force_flush) // important that we get this after the capture buf if (destructive()) { - (*chan).capture_transition_buf->get_read_vector(&transvec); + (*chan)->capture_transition_buf->get_read_vector(&transvec); size_t transcount = transvec.len[0] + transvec.len[1]; bool have_start = false; size_t ti; @@ -1357,8 +1370,8 @@ AudioDiskstream::do_flush (Session::RunContext context, bool force_flush) if (captrans.type == CaptureStart) { // by definition, the first data we got above represents the given capture pos - (*chan).write_source->mark_capture_start (captrans.capture_val); - (*chan).curr_capture_cnt = 0; + (*chan)->write_source->mark_capture_start (captrans.capture_val); + (*chan)->curr_capture_cnt = 0; have_start = true; } @@ -1366,17 +1379,17 @@ AudioDiskstream::do_flush (Session::RunContext context, bool force_flush) // capture end, the capture_val represents total frames in capture - if (captrans.capture_val <= (*chan).curr_capture_cnt + to_write) { + if (captrans.capture_val <= (*chan)->curr_capture_cnt + to_write) { // shorten to make the write a perfect fit - uint32_t nto_write = (captrans.capture_val - (*chan).curr_capture_cnt); + uint32_t nto_write = (captrans.capture_val - (*chan)->curr_capture_cnt); if (nto_write < to_write) { ret = 1; // should we? } to_write = nto_write; - (*chan).write_source->mark_capture_end (); + (*chan)->write_source->mark_capture_end (); // increment past this transition, but go no further ++ti; @@ -1391,17 +1404,17 @@ AudioDiskstream::do_flush (Session::RunContext context, bool force_flush) } if (ti > 0) { - (*chan).capture_transition_buf->increment_read_ptr(ti); + (*chan)->capture_transition_buf->increment_read_ptr(ti); } } - if ((!(*chan).write_source) || (*chan).write_source->write (vector.buf[0], to_write) != 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; } - (*chan).capture_buf->increment_read_ptr (to_write); - (*chan).curr_capture_cnt += to_write; + (*chan)->capture_buf->increment_read_ptr (to_write); + (*chan)->curr_capture_cnt += to_write; if ((to_write == vector.len[0]) && (total > to_write) && (to_write < disk_io_chunk_frames) && !destructive()) { @@ -1412,15 +1425,15 @@ AudioDiskstream::do_flush (Session::RunContext context, bool force_flush) to_write = min ((nframes_t)(disk_io_chunk_frames - to_write), (nframes_t) vector.len[1]); - if ((*chan).write_source->write (vector.buf[1], to_write) != 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; } - _write_data_count += (*chan).write_source->write_data_count(); + _write_data_count += (*chan)->write_source->write_data_count(); - (*chan).capture_buf->increment_read_ptr (to_write); - (*chan).curr_capture_cnt += to_write; + (*chan)->capture_buf->increment_read_ptr (to_write); + (*chan)->curr_capture_cnt += to_write; } } @@ -1440,10 +1453,11 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca SourceList::iterator src; ChannelList::iterator chan; vector<CaptureInfo*>::iterator ci; + boost::shared_ptr<ChannelList> c = channels.reader(); uint32_t n = 0; bool mark_write_completed = false; - finish_capture (true); + finish_capture (true, c); /* butler is already stopped, but there may be work to do to flush remaining data to disk. @@ -1475,13 +1489,13 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca goto outout; } - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { + for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { - if ((*chan).write_source) { + if ((*chan)->write_source) { - (*chan).write_source->mark_for_remove (); - (*chan).write_source->drop_references (); - (*chan).write_source.reset (); + (*chan)->write_source->mark_for_remove (); + (*chan)->write_source->drop_references (); + (*chan)->write_source.reset (); } /* new source set up in "out" below */ @@ -1496,9 +1510,9 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca /* figure out the name for this take */ - for (n = 0, chan = channels.begin(); chan != channels.end(); ++chan, ++n) { + for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) { - boost::shared_ptr<AudioFileSource> s = (*chan).write_source; + boost::shared_ptr<AudioFileSource> s = (*chan)->write_source; if (s) { srcs.push_back (s); @@ -1523,7 +1537,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca } else { string whole_file_region_name; - whole_file_region_name = region_name_from_path (channels[0].write_source->name(), true); + whole_file_region_name = region_name_from_path (c->front()->write_source->name(), true); /* Register a new region with the Session that describes the entire source. Do this first @@ -1532,7 +1546,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca */ try { - boost::shared_ptr<Region> rx (RegionFactory::create (srcs, channels[0].write_source->last_capture_start_frame(), total_capture, + boost::shared_ptr<Region> rx (RegionFactory::create (srcs, c->front()->write_source->last_capture_start_frame(), total_capture, whole_file_region_name, 0, AudioRegion::Flag (AudioRegion::DefaultFlags|AudioRegion::Automatic|AudioRegion::WholeFile))); @@ -1553,7 +1567,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca XMLNode &before = _playlist->get_state(); _playlist->freeze (); - for (buffer_position = channels[0].write_source->last_capture_start_frame(), ci = capture_info.begin(); ci != capture_info.end(); ++ci) { + for (buffer_position = c->front()->write_source->last_capture_start_frame(), ci = capture_info.begin(); ci != capture_info.end(); ++ci) { string region_name; @@ -1603,7 +1617,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca } void -AudioDiskstream::finish_capture (bool rec_monitors_input) +AudioDiskstream::finish_capture (bool rec_monitors_input, boost::shared_ptr<ChannelList> c) { was_recording = false; @@ -1612,16 +1626,16 @@ AudioDiskstream::finish_capture (bool rec_monitors_input) } if (recordable() && destructive()) { - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { + for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { RingBufferNPT<CaptureTransition>::rw_vector transvec; - (*chan).capture_transition_buf->get_write_vector(&transvec); + (*chan)->capture_transition_buf->get_write_vector(&transvec); if (transvec.len[0] > 0) { transvec.buf[0]->type = CaptureEnd; transvec.buf[0]->capture_val = capture_captured; - (*chan).capture_transition_buf->increment_write_ptr(1); + (*chan)->capture_transition_buf->increment_write_ptr(1); } else { // bad! @@ -1664,7 +1678,7 @@ AudioDiskstream::set_record_enabled (bool yn) return; } - if (yn && channels[0].source == 0) { + if (yn && channels.reader()->front()->source == 0) { /* pick up connections not initiated *from* the IO object we're associated with. @@ -1689,23 +1703,24 @@ AudioDiskstream::set_record_enabled (bool yn) void AudioDiskstream::engage_record_enable () { - bool rolling = _session.transport_speed() != 0.0f; + bool rolling = _session.transport_speed() != 0.0f; + boost::shared_ptr<ChannelList> c = channels.reader(); g_atomic_int_set (&_record_enabled, 1); capturing_sources.clear (); if (Config->get_monitoring_model() == HardwareMonitoring) { - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { - if ((*chan).source) { - (*chan).source->ensure_monitor_input (!(Config->get_auto_input() && rolling)); + for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { + if ((*chan)->source) { + (*chan)->source->ensure_monitor_input (!(Config->get_auto_input() && rolling)); } - capturing_sources.push_back ((*chan).write_source); + capturing_sources.push_back ((*chan)->write_source); } } else { - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { - capturing_sources.push_back ((*chan).write_source); + for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { + capturing_sources.push_back ((*chan)->write_source); } } @@ -1716,10 +1731,11 @@ void AudioDiskstream::disengage_record_enable () { g_atomic_int_set (&_record_enabled, 0); - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { + boost::shared_ptr<ChannelList> c = channels.reader(); + for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { if (Config->get_monitoring_model() == HardwareMonitoring) { - if ((*chan).source) { - (*chan).source->ensure_monitor_input (false); + if ((*chan)->source) { + (*chan)->source->ensure_monitor_input (false); } } } @@ -1733,10 +1749,11 @@ AudioDiskstream::get_state () XMLNode* node = new XMLNode ("AudioDiskstream"); char buf[64] = ""; LocaleGuard lg (X_("POSIX")); + boost::shared_ptr<ChannelList> c = channels.reader(); node->add_property ("flags", enum_2_string (_flags)); - snprintf (buf, sizeof(buf), "%zd", channels.size()); + snprintf (buf, sizeof(buf), "%zd", c->size()); node->add_property ("channels", buf); node->add_property ("playlist", _playlist->name()); @@ -1831,21 +1848,15 @@ AudioDiskstream::set_state (const XMLNode& node) // create necessary extra channels // we are always constructed with one and we always need one + _n_channels = channels.reader()->size(); + if (nchans > _n_channels) { - int diff = nchans - channels.size(); - - for (int i=0; i < diff; ++i) { - add_channel (); - } + add_channel (nchans - _n_channels); } else if (nchans < _n_channels) { - int diff = channels.size() - nchans; - - for (int i = 0; i < diff; ++i) { - remove_channel (); - } + remove_channel (_n_channels - nchans); } if ((prop = node.property ("playlist")) == 0) { @@ -1881,8 +1892,6 @@ AudioDiskstream::set_state (const XMLNode& node) } } - _n_channels = channels.size(); - in_set_state = false; /* make sure this is clear before we do anything else */ @@ -1901,38 +1910,40 @@ AudioDiskstream::set_state (const XMLNode& node) int AudioDiskstream::use_new_write_source (uint32_t n) { + boost::shared_ptr<ChannelList> c = channels.reader(); + if (!recordable()) { return 1; } - if (n >= channels.size()) { + if (n >= c->size()) { error << string_compose (_("AudioDiskstream: channel %1 out of range"), n) << endmsg; return -1; } - ChannelInfo &chan = channels[n]; + ChannelInfo* chan = (*c)[n]; - if (chan.write_source) { - chan.write_source->done_with_peakfile_writes (); - chan.write_source->set_allow_remove_if_empty (true); - chan.write_source.reset (); + if (chan->write_source) { + chan->write_source->done_with_peakfile_writes (); + chan->write_source->set_allow_remove_if_empty (true); + chan->write_source.reset (); } try { - if ((chan.write_source = _session.create_audio_source_for_session (*this, n, destructive())) == 0) { + if ((chan->write_source = _session.create_audio_source_for_session (*this, n, destructive())) == 0) { throw failed_constructor(); } } catch (failed_constructor &err) { error << string_compose (_("%1:%2 new capture file not initialized correctly"), _name, n) << endmsg; - chan.write_source.reset (); + chan->write_source.reset (); return -1; } /* do not remove destructive files even if they are empty */ - chan.write_source->set_allow_remove_if_empty (!destructive()); + chan->write_source->set_allow_remove_if_empty (!destructive()); return 0; } @@ -1941,6 +1952,7 @@ void AudioDiskstream::reset_write_sources (bool mark_write_complete, bool force) { ChannelList::iterator chan; + boost::shared_ptr<ChannelList> c = channels.reader(); uint32_t n; if (!recordable()) { @@ -1949,20 +1961,20 @@ AudioDiskstream::reset_write_sources (bool mark_write_complete, bool force) capturing_sources.clear (); - for (chan = channels.begin(), n = 0; chan != channels.end(); ++chan, ++n) { + for (chan = c->begin(), n = 0; chan != c->end(); ++chan, ++n) { if (!destructive()) { - if ((*chan).write_source && mark_write_complete) { - (*chan).write_source->mark_streaming_write_completed (); + if ((*chan)->write_source && mark_write_complete) { + (*chan)->write_source->mark_streaming_write_completed (); } use_new_write_source (n); if (record_enabled()) { - capturing_sources.push_back ((*chan).write_source); + capturing_sources.push_back ((*chan)->write_source); } } else { - if ((*chan).write_source == 0) { + if ((*chan)->write_source == 0) { use_new_write_source (n); } } @@ -1984,11 +1996,12 @@ int AudioDiskstream::rename_write_sources () { ChannelList::iterator chan; + boost::shared_ptr<ChannelList> c = channels.reader(); uint32_t n; - for (chan = channels.begin(), n = 0; chan != channels.end(); ++chan, ++n) { - if ((*chan).write_source != 0) { - (*chan).write_source->set_name (_name, destructive()); + for (chan = c->begin(), n = 0; chan != c->end(); ++chan, ++n) { + if ((*chan)->write_source != 0) { + (*chan)->write_source->set_name (_name, destructive()); /* XXX what to do if one of them fails ? */ } } @@ -2001,10 +2014,11 @@ AudioDiskstream::set_block_size (nframes_t nframes) { if (_session.get_block_size() > speed_buffer_size) { speed_buffer_size = _session.get_block_size(); + boost::shared_ptr<ChannelList> c = channels.reader(); - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { - if ((*chan).speed_buffer) delete [] (*chan).speed_buffer; - (*chan).speed_buffer = new Sample[speed_buffer_size]; + for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { + if ((*chan)->speed_buffer) delete [] (*chan)->speed_buffer; + (*chan)->speed_buffer = new Sample[speed_buffer_size]; } } allocate_temporary_buffers (); @@ -2023,11 +2037,13 @@ AudioDiskstream::allocate_temporary_buffers () if (required_wrap_size > wrap_buffer_size) { - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { - if ((*chan).playback_wrap_buffer) delete [] (*chan).playback_wrap_buffer; - (*chan).playback_wrap_buffer = new Sample[required_wrap_size]; - if ((*chan).capture_wrap_buffer) delete [] (*chan).capture_wrap_buffer; - (*chan).capture_wrap_buffer = new Sample[required_wrap_size]; + boost::shared_ptr<ChannelList> c = channels.reader(); + + for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { + if ((*chan)->playback_wrap_buffer) delete [] (*chan)->playback_wrap_buffer; + (*chan)->playback_wrap_buffer = new Sample[required_wrap_size]; + if ((*chan)->capture_wrap_buffer) delete [] (*chan)->capture_wrap_buffer; + (*chan)->capture_wrap_buffer = new Sample[required_wrap_size]; } wrap_buffer_size = required_wrap_size; @@ -2037,10 +2053,12 @@ AudioDiskstream::allocate_temporary_buffers () void AudioDiskstream::monitor_input (bool yn) { - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { + boost::shared_ptr<ChannelList> c = channels.reader(); + + for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { - if ((*chan).source) { - (*chan).source->ensure_monitor_input (yn); + if ((*chan)->source) { + (*chan)->source->ensure_monitor_input (yn); } } } @@ -2056,8 +2074,10 @@ AudioDiskstream::set_align_style_from_io () get_input_sources (); - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { - if ((*chan).source && (*chan).source->flags() & JackPortIsPhysical) { + boost::shared_ptr<ChannelList> c = channels.reader(); + + for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { + if ((*chan)->source && (*chan)->source->flags() & JackPortIsPhysical) { have_physical = true; break; } @@ -2071,55 +2091,64 @@ AudioDiskstream::set_align_style_from_io () } int -AudioDiskstream::add_channel () +AudioDiskstream::add_channel_to (boost::shared_ptr<ChannelList> c, uint32_t how_many) { - /* XXX need to take lock??? */ + while (how_many--) { + c->push_back (new ChannelInfo(_session.diskstream_buffer_size(), speed_buffer_size, wrap_buffer_size)); + } - /* this copies the ChannelInfo, which currently has no buffers. kind - of pointless really, but we want the channels list to contain - actual objects, not pointers to objects. mostly for convenience, - which isn't much in evidence. - */ + _n_channels = c->size(); - channels.push_back (ChannelInfo()); + return 0; +} - /* now allocate the buffers */ +int +AudioDiskstream::add_channel (uint32_t how_many) +{ + RCUWriter<ChannelList> writer (channels); + boost::shared_ptr<ChannelList> c = writer.get_copy(); + + return add_channel_to (c, how_many); +} - channels.back().init (_session.diskstream_buffer_size(), - speed_buffer_size, - wrap_buffer_size); +int +AudioDiskstream::remove_channel_from (boost::shared_ptr<ChannelList> c, uint32_t how_many) +{ + while (--how_many && !c->empty()) { + delete c->back(); + c->pop_back(); + } - _n_channels = channels.size(); + _n_channels = c->size(); return 0; } int -AudioDiskstream::remove_channel () +AudioDiskstream::remove_channel (uint32_t how_many) { - if (channels.size() > 1) { - /* XXX need to take lock??? */ - channels.back().release (); - channels.pop_back(); - _n_channels = channels.size(); - return 0; - } - - return -1; + RCUWriter<ChannelList> writer (channels); + boost::shared_ptr<ChannelList> c = writer.get_copy(); + + return remove_channel_from (c, how_many); } float AudioDiskstream::playback_buffer_load () const { - return (float) ((double) channels.front().playback_buf->read_space()/ - (double) channels.front().playback_buf->bufsize()); + boost::shared_ptr<ChannelList> c = channels.reader(); + + return (float) ((double) c->front()->playback_buf->read_space()/ + (double) c->front()->playback_buf->bufsize()); } float AudioDiskstream::capture_buffer_load () const { - return (float) ((double) channels.front().capture_buf->write_space()/ - (double) channels.front().capture_buf->bufsize()); + boost::shared_ptr<ChannelList> c = channels.reader(); + + return (float) ((double) c->front()->capture_buf->write_space()/ + (double) c->front()->capture_buf->bufsize()); } int @@ -2281,24 +2310,14 @@ AudioDiskstream::can_become_destructive (bool& requires_bounce) const return true; } -AudioDiskstream::ChannelInfo::ChannelInfo () +AudioDiskstream::ChannelInfo::ChannelInfo (nframes_t bufsize, nframes_t speed_size, nframes_t wrap_size) { - playback_wrap_buffer = 0; - capture_wrap_buffer = 0; - speed_buffer = 0; peak_power = 0.0f; source = 0; current_capture_buffer = 0; current_playback_buffer = 0; curr_capture_cnt = 0; - playback_buf = 0; - capture_buf = 0; - capture_transition_buf = 0; -} -void -AudioDiskstream::ChannelInfo::init (nframes_t bufsize, nframes_t speed_size, nframes_t wrap_size) -{ speed_buffer = new Sample[speed_size]; playback_wrap_buffer = new Sample[wrap_size]; capture_wrap_buffer = new Sample[wrap_size]; @@ -2320,11 +2339,6 @@ AudioDiskstream::ChannelInfo::init (nframes_t bufsize, nframes_t speed_size, nfr AudioDiskstream::ChannelInfo::~ChannelInfo () { -} - -void -AudioDiskstream::ChannelInfo::release () -{ if (write_source) { write_source.reset (); } diff --git a/libs/ardour/auditioner.cc b/libs/ardour/auditioner.cc index 5548e3cc5d..e6f4e12e3d 100644 --- a/libs/ardour/auditioner.cc +++ b/libs/ardour/auditioner.cc @@ -64,7 +64,7 @@ Auditioner::Auditioner (Session& s) } if (right.length()) { - audio_diskstream()->add_channel(); + audio_diskstream()->add_channel (1); add_output_port (right, this, DataType::AUDIO); } @@ -138,12 +138,10 @@ Auditioner::audition_region (boost::shared_ptr<Region> region) _diskstream->playlist()->clear (); _diskstream->playlist()->add_region (the_region, 0, 1); - while (_diskstream->n_channels() < the_region->n_channels()) { - audio_diskstream()->add_channel (); - } - - while (_diskstream->n_channels() > the_region->n_channels()) { - audio_diskstream()->remove_channel (); + if (_diskstream->n_channels() < the_region->n_channels()) { + audio_diskstream()->add_channel (the_region->n_channels() - _diskstream->n_channels()); + } else if (_diskstream->n_channels() > the_region->n_channels()) { + audio_diskstream()->remove_channel (_diskstream->n_channels() - the_region->n_channels()); } /* force a panner reset now that we have all channels */ diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc index f643bbe2c0..135718bb52 100644 --- a/libs/ardour/diskstream.cc +++ b/libs/ardour/diskstream.cc @@ -143,7 +143,7 @@ Diskstream::handle_input_change (IOChange change, void *src) if (!(input_change_pending & change)) { input_change_pending = IOChange (input_change_pending|change); - _session.request_input_change_handling (shared_from_this()); + _session.request_input_change_handling (); } } diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 951339db98..129fa5f743 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -269,7 +269,6 @@ Session::Session (AudioEngine &eng, pending_events (2048), midi_requests (128), // the size of this should match the midi request pool size diskstreams (new DiskstreamList), - diskstreams_input_pending (new DiskstreamList), routes (new RouteList), auditioner ((Auditioner*) 0), _click_io ((IO*) 0), @@ -333,7 +332,6 @@ Session::Session (AudioEngine &eng, pending_events (2048), midi_requests (16), diskstreams (new DiskstreamList), - diskstreams_input_pending (new DiskstreamList), routes (new RouteList), main_outs (0) @@ -2008,7 +2006,7 @@ Session::add_diskstream (boost::shared_ptr<Diskstream> dstream) dstream->set_block_size (current_block_size); - if (_state_of_the_state & InitialConnecting) { + { RCUWriter<DiskstreamList> writer (diskstreams); boost::shared_ptr<DiskstreamList> ds = writer.get_copy(); ds->push_back (dstream); @@ -3387,11 +3385,7 @@ Session::graph_reordered () we were connecting. do it now. */ - boost::shared_ptr<DiskstreamList> ds = diskstreams.reader(); - - for (DiskstreamList::iterator i = ds->begin(); i != ds->end(); ++i) { - request_input_change_handling (*i); - } + request_input_change_handling (); resort_routes (); diff --git a/libs/ardour/session_events.cc b/libs/ardour/session_events.cc index 416d72969e..e93a7a5f17 100644 --- a/libs/ardour/session_events.cc +++ b/libs/ardour/session_events.cc @@ -410,18 +410,6 @@ Session::process_event (Event* ev) case Event::InputConfigurationChange: post_transport_work = PostTransportWork (post_transport_work | PostTransportInputChange); - { - RCUWriter<DiskstreamList> writer (diskstreams); - boost::shared_ptr<DiskstreamList> ds = writer.get_copy(); - ds->remove (ev->diskstream); - /* writer goes out of scope, copies ds back to main */ - } - { - RCUWriter<DiskstreamList> writer (diskstreams_input_pending); - boost::shared_ptr<DiskstreamList> ds = writer.get_copy(); - ds->push_back (ev->diskstream); - /* writer goes out of scope, copies ds back to main */ - } schedule_butler_transport_work (); break; diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 17a6806c52..c0468a63ca 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -49,11 +49,10 @@ using namespace sigc; using namespace PBD; void -Session::request_input_change_handling (boost::shared_ptr<Diskstream> ds) +Session::request_input_change_handling () { if (!(_state_of_the_state & (InitialConnecting|Deletion))) { Event* ev = new Event (Event::InputConfigurationChange, Event::Add, Event::Immediate, 0, 0.0); - ev->diskstream = ds; queue_event (ev); } } @@ -197,27 +196,9 @@ Session::butler_transport_work () } if (post_transport_work & PostTransportInputChange) { - { - RCUWriter<DiskstreamList> input_writer (diskstreams_input_pending); - boost::shared_ptr<DiskstreamList> input_list = input_writer.get_copy (); - RCUWriter<DiskstreamList> dswriter (diskstreams); - boost::shared_ptr<DiskstreamList> ds = dswriter.get_copy(); - - for (DiskstreamList::iterator i = input_list->begin(); i != input_list->end(); ++i) { - - /* make the change */ - - (*i)->non_realtime_input_change (); - - /* now transfer it back onto the regular diskstreams list */ - - ds->push_back (*i); - } - - input_list->clear(); + for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { + (*i)->non_realtime_input_change (); } - - diskstreams_input_pending.flush (); } if (post_transport_work & PostTransportSpeed) { |