X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Faudio_diskstream.cc;h=77c14de10338f07396a5caf7de59b5c0f8742ea6;hb=616f2a0370a10dcc7372a95f6bca9f5a45698980;hp=a7c8558fdc7027aaeaa1dd26b74d1b1ef253ba16;hpb=7bdcc127e3e42bd76b997b56ecd938b1127d790b;p=ardour.git diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index a7c8558fdc..77c14de103 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -37,29 +37,24 @@ #include "pbd/stateful_diff_command.h" #include "ardour/analyser.h" -#include "ardour/ardour.h" #include "ardour/audio_buffer.h" #include "ardour/audio_diskstream.h" #include "ardour/audio_port.h" #include "ardour/audioengine.h" #include "ardour/audiofilesource.h" - #include "ardour/audioplaylist.h" #include "ardour/audioregion.h" #include "ardour/butler.h" -#include "ardour/configuration.h" -#include "ardour/cycle_timer.h" #include "ardour/debug.h" #include "ardour/io.h" #include "ardour/playlist_factory.h" #include "ardour/region_factory.h" -#include "ardour/send.h" #include "ardour/session.h" +#include "ardour/session_playlists.h" #include "ardour/source_factory.h" #include "ardour/track.h" +#include "ardour/types.h" #include "ardour/utils.h" -#include "ardour/session_playlists.h" -#include "ardour/route.h" #include "i18n.h" #include @@ -156,7 +151,7 @@ void AudioDiskstream::non_realtime_input_change () { { - Glib::Mutex::Lock lm (state_lock); + Glib::Threads::Mutex::Lock lm (state_lock); if (input_change_pending.type == IOChange::NoChange) { return; @@ -281,7 +276,6 @@ AudioDiskstream::use_new_playlist () if ((playlist = boost::dynamic_pointer_cast (PlaylistFactory::create (DataType::AUDIO, _session, newname, hidden()))) != 0) { - playlist->set_orig_diskstream_id (id()); return use_playlist (playlist); } else { @@ -309,7 +303,6 @@ AudioDiskstream::use_copy_playlist () newname = Playlist::bump_name (_playlist->name(), _session); if ((playlist = boost::dynamic_pointer_cast(PlaylistFactory::create (audio_playlist(), newname))) != 0) { - playlist->set_orig_diskstream_id (id()); return use_playlist (playlist); } else { return -1; @@ -405,13 +398,21 @@ AudioDiskstream::prepare_record_status(framepos_t capture_start_frame) } } + +/** Do some record stuff [not described in this comment!] + * + * Also: + * - Setup playback_distance with the nframes, or nframes adjusted + * for current varispeed, if appropriate. + * - Setup current_playback_buffer in each ChannelInfo to point to data + * that someone can read playback_distance worth of data from. + */ int -AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool& need_butler) +AudioDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t nframes, framecnt_t& playback_distance, bool need_disk_signal) { uint32_t n; boost::shared_ptr c = channels.reader(); ChannelList::iterator chan; - int ret = -1; framecnt_t rec_offset = 0; framecnt_t rec_nframes = 0; bool collect_playback = false; @@ -429,7 +430,7 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool& n return 0; } - Glib::Mutex::Lock sm (state_lock, Glib::TRY_LOCK); + Glib::Threads::Mutex::Lock sm (state_lock, Glib::Threads::TRY_LOCK); if (!sm.locked()) { return 1; @@ -451,7 +452,7 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool& n if (record_enabled()) { - OverlapType ot = coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes); + Evoral::OverlapType ot = Evoral::coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes); calculate_record_range (ot, transport_frame, nframes, rec_nframes, rec_offset); if (rec_nframes && !was_recording) { @@ -493,22 +494,22 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool& n assert(ap); assert(rec_nframes <= (framecnt_t) ap->get_audio_buffer(nframes).capacity()); - Sample *buf = ap->get_audio_buffer (nframes).data (rec_offset); + Sample *buf = bufs.get_audio (n).data(rec_offset); memcpy (chaninfo->current_capture_buffer, buf, sizeof (Sample) * rec_nframes); - + } else { framecnt_t total = chaninfo->capture_vector.len[0] + chaninfo->capture_vector.len[1]; if (rec_nframes > total) { DiskOverrun (); - goto out; + return -1; } boost::shared_ptr const ap = _io->audio (n); assert(ap); - Sample* buf = ap->get_audio_buffer(nframes).data (rec_offset); + Sample *buf = bufs.get_audio (n).data(rec_offset); framecnt_t first = chaninfo->capture_vector.len[0]; memcpy (chaninfo->capture_wrap_buffer, buf, sizeof (Sample) * first); @@ -577,7 +578,7 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool& n /* no varispeed playback if we're recording, because the output .... TBD */ if (rec_nframes == 0 && _actual_speed != 1.0f) { - necessary_samples = (framecnt_t) floor ((nframes * fabs (_actual_speed))) + 1; + necessary_samples = (framecnt_t) ceil ((nframes * fabs (_actual_speed))) + 2; } else { necessary_samples = nframes; } @@ -588,12 +589,17 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool& n n = 0; + /* Setup current_playback_buffer in each ChannelInfo to point to data that someone + can read necessary_samples (== nframes at a transport speed of 1) worth of data + from right now. + */ + for (chan = c->begin(); chan != c->end(); ++chan, ++n) { ChannelInfo* chaninfo (*chan); if (necessary_samples <= (framecnt_t) chaninfo->playback_vector.len[0]) { - + /* There are enough samples in the first part of the ringbuffer */ chaninfo->current_playback_buffer = chaninfo->playback_vector.buf[0]; } else { @@ -603,13 +609,23 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool& n cerr << _name << " Need " << necessary_samples << " total = " << total << endl; cerr << "underrun for " << _name << endl; DiskUnderrun (); - goto out; + return -1; } else { + /* We have enough samples, but not in one lump. Coalesce the two parts + into one in playback_wrap_buffer in our ChannelInfo, and specify that + as our current_playback_buffer. + */ + + assert(wrap_buffer_size >= necessary_samples); + + /* Copy buf[0] from playback_buf */ memcpy ((char *) chaninfo->playback_wrap_buffer, chaninfo->playback_vector.buf[0], chaninfo->playback_vector.len[0] * sizeof (Sample)); + + /* Copy buf[1] from playback_buf */ memcpy (chaninfo->playback_wrap_buffer + chaninfo->playback_vector.len[0], chaninfo->playback_vector.buf[1], (necessary_samples - chaninfo->playback_vector.len[0]) @@ -621,45 +637,100 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool& n } if (rec_nframes == 0 && _actual_speed != 1.0f && _actual_speed != -1.0f) { - process_varispeed_playback(nframes, c); + + interpolation.set_speed (_target_speed); + + int channel = 0; + for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan, ++channel) { + ChannelInfo* chaninfo (*chan); + + playback_distance = interpolation.interpolate ( + channel, nframes, chaninfo->current_playback_buffer, chaninfo->speed_buffer); + + chaninfo->current_playback_buffer = chaninfo->speed_buffer; + } + } else { playback_distance = nframes; } _speed = _target_speed; - } - ret = 0; + if (need_disk_signal) { + + /* copy data over to buffer set */ + + size_t n_buffers = bufs.count().n_audio(); + size_t n_chans = c->size(); + gain_t scaling = 1.0f; + + if (n_chans > n_buffers) { + scaling = ((float) n_buffers)/n_chans; + } - if (commit (nframes)) { - need_butler = true; + for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) { + + AudioBuffer& buf (bufs.get_audio (n%n_buffers)); + ChannelInfo* chaninfo (*chan); + + if (n < n_chans) { + if (scaling != 1.0f) { + buf.read_from_with_gain (chaninfo->current_playback_buffer, nframes, scaling); + } else { + buf.read_from (chaninfo->current_playback_buffer, nframes); + } + } else { + if (scaling != 1.0f) { + buf.accumulate_with_gain_from (chaninfo->current_playback_buffer, nframes, scaling); + } else { + buf.accumulate_from (chaninfo->current_playback_buffer, nframes); + } + } + } + + /* leave the MIDI count alone */ + ChanCount cnt (DataType::AUDIO, n_chans); + cnt.set (DataType::MIDI, bufs.count().n_midi()); + bufs.set_count (cnt); + + /* extra buffers will already be silent, so leave them alone */ } - out: - return ret; + return 0; } -void -AudioDiskstream::process_varispeed_playback (pframes_t nframes, boost::shared_ptr c) +frameoffset_t +AudioDiskstream::calculate_playback_distance (pframes_t nframes) { - ChannelList::iterator chan; - - interpolation.set_speed (_target_speed); - - int channel = 0; - for (chan = c->begin(); chan != c->end(); ++chan, ++channel) { - ChannelInfo* chaninfo (*chan); + frameoffset_t playback_distance = nframes; - playback_distance = interpolation.interpolate ( - channel, nframes, chaninfo->current_playback_buffer, chaninfo->speed_buffer); + if (record_enabled()) { + playback_distance = nframes; + } else if (_actual_speed != 1.0f && _actual_speed != -1.0f) { + interpolation.set_speed (_target_speed); + boost::shared_ptr c = channels.reader(); + int channel = 0; + for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan, ++channel) { + playback_distance = interpolation.interpolate (channel, nframes, NULL, NULL); + } + } else { + playback_distance = nframes; + } - chaninfo->current_playback_buffer = chaninfo->speed_buffer; + if (_actual_speed < 0.0) { + return -playback_distance; + } else { + return playback_distance; } } +/** Update various things including playback_sample, read pointer on each channel's playback_buf + * and write pointer on each channel's capture_buf. Also wout whether the butler is needed. + * @return true if the butler is required. + */ bool -AudioDiskstream::commit (framecnt_t /* nframes */) +AudioDiskstream::commit (framecnt_t playback_distance) { bool need_butler = false; @@ -773,7 +844,7 @@ AudioDiskstream::overwrite_existing_buffers () framecnt_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, n, reversed)) { error << string_compose(_("AudioDiskstream %1: when refilling, cannot read %2 from playlist at frame %3"), id(), size, playback_sample) << endmsg; goto out; @@ -783,8 +854,7 @@ AudioDiskstream::overwrite_existing_buffers () cnt -= to_read; - if (read ((*chan)->playback_buf->buffer(), mixdown_buffer, gain_buffer, - start, cnt, *chan, n, reversed)) { + if (read ((*chan)->playback_buf->buffer(), mixdown_buffer, gain_buffer, start, cnt, n, reversed)) { error << string_compose(_("AudioDiskstream %1: when refilling, cannot read %2 from playlist at frame %3"), id(), size, playback_sample) << endmsg; goto out; @@ -809,7 +879,7 @@ AudioDiskstream::seek (framepos_t frame, bool complete_refill) ChannelList::iterator chan; boost::shared_ptr c = channels.reader(); - Glib::Mutex::Lock lm (state_lock); + Glib::Threads::Mutex::Lock lm (state_lock); for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) { (*chan)->playback_buf->reset (); @@ -855,7 +925,7 @@ AudioDiskstream::internal_playback_seek (framecnt_t distance) boost::shared_ptr c = channels.reader(); for (chan = c->begin(); chan != c->end(); ++chan) { - (*chan)->playback_buf->increment_read_ptr (distance); + (*chan)->playback_buf->increment_read_ptr (llabs(distance)); } if (first_recordable_frame < max_framepos) { @@ -866,10 +936,17 @@ AudioDiskstream::internal_playback_seek (framecnt_t distance) return 0; } +/** Read some data for 1 channel from our playlist into a buffer. + * @param buf Buffer to write to. + * @param start Session frame to start reading from; updated to where we end up + * after the read. + * @param cnt Count of samples to read. + * @param reversed true if we are running backwards, otherwise false. + */ int AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, framepos_t& start, framecnt_t cnt, - ChannelInfo* /*channel_info*/, int channel, bool reversed) + int channel, bool reversed) { framecnt_t this_read = 0; bool reloop = false; @@ -903,25 +980,24 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, */ if (loc && start >= loop_end) { - //cerr << "start adjusted from " << start; start = loop_start + ((start - loop_start) % loop_length); - //cerr << "to " << start << endl; } - - //cerr << "start is " << start << " loopstart: " << loop_start << " loopend: " << loop_end << endl; } if (reversed) { start -= cnt; } + /* We need this while loop in case we hit a loop boundary, in which case our read from + the playlist must be split into more than one section. + */ + while (cnt) { /* take any loop into account. we can't read past the end of the loop. */ if (loc && (loop_end - start < cnt)) { this_read = loop_end - start; - //cerr << "reloop true: thisread: " << this_read << " cnt: " << cnt << endl; reloop = true; } else { reloop = false; @@ -976,13 +1052,16 @@ AudioDiskstream::do_refill_with_alloc () return ret; } +/** Get some more data from disk and put it in our channels' playback_bufs, + * if there is suitable space in them. + */ int AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer) { int32_t ret = 0; framecnt_t to_read; RingBufferNPT::rw_vector vector; - bool reversed = (_visible_speed * _session.transport_speed()) < 0.0f; + bool const reversed = (_visible_speed * _session.transport_speed()) < 0.0f; framecnt_t total_space; framecnt_t zero_fill; uint32_t chan_n; @@ -1005,6 +1084,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer) c->front()->playback_buf->get_write_vector (&vector); if ((total_space = vector.len[0] + vector.len[1]) == 0) { + /* nowhere to write to */ return 0; } @@ -1013,7 +1093,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer) for us to be called again, ASAP. */ - if (total_space >= (_slaved?3:2) * disk_io_chunk_frames) { + if (total_space >= (_slaved ? 3 : 2) * disk_io_chunk_frames) { ret = 1; } @@ -1158,7 +1238,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer) if (to_read) { - if (read (buf1, mixdown_buffer, gain_buffer, file_frame_tmp, to_read, chan, chan_n, reversed)) { + if (read (buf1, mixdown_buffer, gain_buffer, file_frame_tmp, to_read, chan_n, reversed)) { ret = -1; goto out; } @@ -1175,7 +1255,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer) so read some or all of vector.len[1] as well. */ - if (read (buf2, mixdown_buffer, gain_buffer, file_frame_tmp, to_read, chan, chan_n, reversed)) { + if (read (buf2, mixdown_buffer, gain_buffer, file_frame_tmp, to_read, chan_n, reversed)) { ret = -1; goto out; } @@ -1184,7 +1264,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer) } if (zero_fill) { - /* do something */ + /* XXX: do something */ } } @@ -1366,7 +1446,7 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo } /* XXX is there anything we can do if err != 0 ? */ - Glib::Mutex::Lock lm (capture_info_lock); + Glib::Threads::Mutex::Lock lm (capture_info_lock); if (capture_info.empty()) { return; @@ -1463,6 +1543,7 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo // cerr << _name << ": there are " << capture_info.size() << " capture_info records\n"; _playlist->clear_changes (); + _playlist->set_capture_insertion_in_progress (true); _playlist->freeze (); for (buffer_position = c->front()->write_source->last_capture_start_frame(), ci = capture_info.begin(); ci != capture_info.end(); ++ci) { @@ -1493,21 +1574,15 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo i_am_the_modifier++; - if (_playlist->explicit_relayering()) { - /* We are in `explicit relayering' mode, so we must specify which layer this new region - should end up on. Put it at the top. - */ - region->set_layer (_playlist->top_layer() + 1); - region->set_pending_explicit_relayer (true); - } - _playlist->add_region (region, (*ci)->start, 1, non_layered()); + _playlist->set_layer (region, DBL_MAX); i_am_the_modifier--; buffer_position += (*ci)->frames; } _playlist->thaw (); + _playlist->set_capture_insertion_in_progress (false); _session.add_command (new StatefulDiffCommand (_playlist)); } @@ -1653,22 +1728,33 @@ AudioDiskstream::set_record_enabled (bool yn) } else { disengage_record_enable (); } + + RecordEnableChanged (); /* EMIT SIGNAL */ } } -void -AudioDiskstream::engage_record_enable () +bool +AudioDiskstream::prep_record_enable () { + if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_audio() == 0) { + return false; + } + + /* can't rec-enable in destructive mode if transport is before start */ + + if (destructive() && _session.transport_frame() < _session.current_start_frame()) { + return false; + } + bool rolling = _session.transport_speed() != 0.0f; boost::shared_ptr c = channels.reader(); - g_atomic_int_set (&_record_enabled, 1); capturing_sources.clear (); if (Config->get_monitoring_model() == HardwareMonitoring) { for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { - (*chan)->source.ensure_monitor_input (!(_session.config.get_auto_input() && rolling)); + (*chan)->source.request_input_monitoring (!(_session.config.get_auto_input() && rolling)); capturing_sources.push_back ((*chan)->write_source); (*chan)->write_source->mark_streaming_write_started (); } @@ -1680,21 +1766,21 @@ AudioDiskstream::engage_record_enable () } } - RecordEnableChanged (); /* EMIT SIGNAL */ + return true; } -void -AudioDiskstream::disengage_record_enable () +bool +AudioDiskstream::prep_record_disable () { - g_atomic_int_set (&_record_enabled, 0); boost::shared_ptr c = channels.reader(); if (Config->get_monitoring_model() == HardwareMonitoring) { for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { - (*chan)->source.ensure_monitor_input (false); + (*chan)->source.request_input_monitoring (false); } } capturing_sources.clear (); - RecordEnableChanged (); /* EMIT SIGNAL */ + + return true; } XMLNode& @@ -1933,18 +2019,20 @@ AudioDiskstream::allocate_temporary_buffers () */ double const sp = max (fabsf (_actual_speed), 1.2f); - framecnt_t required_wrap_size = (framecnt_t) floor (_session.get_block_size() * sp) + 1; + framecnt_t required_wrap_size = (framecnt_t) ceil (_session.get_block_size() * sp) + 2; if (required_wrap_size > wrap_buffer_size) { boost::shared_ptr c = channels.reader(); for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { - if ((*chan)->playback_wrap_buffer) + if ((*chan)->playback_wrap_buffer) { delete [] (*chan)->playback_wrap_buffer; + } (*chan)->playback_wrap_buffer = new Sample[required_wrap_size]; - if ((*chan)->capture_wrap_buffer) + if ((*chan)->capture_wrap_buffer) { delete [] (*chan)->capture_wrap_buffer; + } (*chan)->capture_wrap_buffer = new Sample[required_wrap_size]; } @@ -1953,12 +2041,12 @@ AudioDiskstream::allocate_temporary_buffers () } void -AudioDiskstream::monitor_input (bool yn) +AudioDiskstream::request_input_monitoring (bool yn) { boost::shared_ptr c = channels.reader(); for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { - (*chan)->source.ensure_monitor_input (yn); + (*chan)->source.request_input_monitoring (yn); } } @@ -2105,7 +2193,7 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node) fs = boost::dynamic_pointer_cast ( SourceFactory::createWritable ( DataType::AUDIO, _session, - prop->value(), string(), false, _session.frame_rate())); + prop->value(), false, _session.frame_rate())); } catch (failed_constructor& err) { @@ -2281,18 +2369,17 @@ AudioDiskstream::ChannelSource::is_physical () const } void -AudioDiskstream::ChannelSource::ensure_monitor_input (bool yn) const +AudioDiskstream::ChannelSource::request_input_monitoring (bool yn) const { if (name.empty()) { return; } - return AudioEngine::instance()->ensure_monitor_input (name, yn); + return AudioEngine::instance()->request_input_monitoring (name, yn); } AudioDiskstream::ChannelInfo::ChannelInfo (framecnt_t playback_bufsize, framecnt_t capture_bufsize, framecnt_t speed_size, framecnt_t wrap_size) { - peak_power = 0.0f; current_capture_buffer = 0; current_playback_buffer = 0; curr_capture_cnt = 0;