diff --git a/libs/ardour/ardour/destructive_filesource.h b/libs/ardour/ardour/destructive_filesource.h index 0663d7f034..bb46fdfd22 100644 --- a/libs/ardour/ardour/destructive_filesource.h +++ b/libs/ardour/ardour/destructive_filesource.h @@ -36,7 +36,8 @@ class DestructiveFileSource : public FileSource { ~DestructiveFileSource (); int seek (jack_nframes_t frame); - void mark_capture_start (); + jack_nframes_t last_capture_start_frame() const; + void mark_capture_start (jack_nframes_t); void mark_capture_end (); void clear_capture_marks(); @@ -50,6 +51,7 @@ class DestructiveFileSource : public FileSource { bool _capture_start; bool _capture_end; + jack_nframes_t capture_start_frame; jack_nframes_t file_pos; Sample* xfade_buf; diff --git a/libs/ardour/ardour/filesource.h b/libs/ardour/ardour/filesource.h index fc86656c2e..e426159014 100644 --- a/libs/ardour/ardour/filesource.h +++ b/libs/ardour/ardour/filesource.h @@ -56,6 +56,12 @@ class FileSource : public Source { string old_peak_path(string audio_path); string path() const { return _path; } + virtual int seek (jack_nframes_t frame) {return 0; } + virtual jack_nframes_t last_capture_start_frame() const { return 0; } + virtual void mark_capture_start (jack_nframes_t) {} + virtual void mark_capture_end () {} + virtual void clear_capture_marks() {} + int update_header (jack_nframes_t when, struct tm&, time_t); int move_to_trash (const string trash_dir_name); diff --git a/libs/ardour/destructive_filesource.cc b/libs/ardour/destructive_filesource.cc index 186166e08c..6df6ff06af 100644 --- a/libs/ardour/destructive_filesource.cc +++ b/libs/ardour/destructive_filesource.cc @@ -52,6 +52,7 @@ typedef off_t off64_t; #include #include +#include #include #include @@ -108,22 +109,24 @@ DestructiveFileSource::setup_standard_crossfades (jack_nframes_t rate) /* XXXX THIS IS NOT THE RIGHT XFADE CURVE: USE A PROPER VOLUMETRIC EQUAL POWER CURVE */ - out_coefficient[n] = n/(gain_t) xfade_frames; - in_coefficient[n] = 1.0 - out_coefficient[n]; + in_coefficient[n] = n/(gain_t) (xfade_frames-1); /* 0 .. 1 */ + out_coefficient[n] = 1.0 - in_coefficient[n]; /* 1 .. 0 */ } } int DestructiveFileSource::seek (jack_nframes_t frame) { - file_pos = data_offset + (sizeof (Sample) * frame); +// file_pos = data_offset + (sizeof (Sample) * frame); + cerr << _name << " Seek to " << frame << " = " << data_offset + (sizeof (Sample) * frame) << endl; return 0; } void -DestructiveFileSource::mark_capture_start () +DestructiveFileSource::mark_capture_start (jack_nframes_t pos) { _capture_start = true; + capture_start_frame = pos; } void @@ -140,67 +143,97 @@ DestructiveFileSource::clear_capture_marks () } jack_nframes_t -DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int dir) +DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in) { jack_nframes_t xfade = min (xfade_frames, cnt); jack_nframes_t xfade_bytes = xfade * sizeof (Sample); - - if (::pread64 (fd, (char *) xfade_buf, xfade_bytes, file_pos) != (off64_t) xfade_bytes) { - error << string_compose(_("FileSource: \"%1\" bad read (%2)"), _path, strerror (errno)) << endmsg; - return 0; - } - - if (xfade == xfade_frames) { - - /* use the standard xfade curve */ - - if (dir) { - - /* fade new material in */ - - for (jack_nframes_t n = 0; n < xfade; ++n) { - xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (data[n] * in_coefficient[n]); - } - } else { - - /* fade new material out */ - - - for (jack_nframes_t n = 0; n < xfade; ++n) { - xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (data[n] * out_coefficient[n]); - } - } - + jack_nframes_t nofade = cnt - xfade; + jack_nframes_t nofade_bytes = nofade * sizeof (Sample); + Sample* fade_data = 0; + off_t fade_position = 0; + if (fade_in) { + fade_position = file_pos; + fade_data = data; } else { + fade_position = file_pos + nofade_bytes; + fade_data = data + nofade; + } - /* short xfade, compute custom curve */ + if (::pread64 (fd, (char *) xfade_buf, xfade_bytes, fade_position) != (off64_t) xfade_bytes) { + if (errno == EAGAIN) { + /* no data there, so no xfade */ - for (jack_nframes_t n = 0; n < xfade; ++n) { - xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (data[n] * in_coefficient[n]); + xfade = 0; + xfade_bytes = 0; + nofade = cnt; + nofade_bytes = nofade * sizeof (Sample); + + } else { + error << string_compose(_("FileSource: \"%1\" bad read (%2: %3)"), _path, errno, strerror (errno)) << endmsg; + return 0; } } - - if (::pwrite64 (fd, (char *) xfade_buf, xfade, file_pos) != (off64_t) xfade_bytes) { - error << string_compose(_("FileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg; - return 0; - } - /* don't advance file_pos here; if the write fails, we want it left where it was before the overall - write, not in the middle of it. - */ - - if (xfade < cnt) { - jack_nframes_t remaining = (cnt - xfade); - int32_t bytes = remaining * sizeof (Sample); - - if (::pwrite64 (fd, (char *) data + remaining, bytes, file_pos) != (off64_t) bytes) { + if (nofade && !fade_in) { + cerr << "write " << nofade_bytes << " of prefade OUT data to " << file_pos << " .. " << file_pos + nofade_bytes << endl; + if (::pwrite64 (fd, (char *) data, nofade_bytes, file_pos) != (off64_t) nofade_bytes) { error << string_compose(_("FileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg; return 0; } } - file_pos += cnt; + if (xfade == xfade_frames) { + + jack_nframes_t n; + + /* use the standard xfade curve */ + + if (fade_in) { + + /* fade new material in */ + + for (n = 0; n < xfade; ++n) { + xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]); + } + + } else { + + + /* fade new material out */ + + for (n = 0; n < xfade; ++n) { + xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]); + } + } + + } else if (xfade) { + + /* short xfade, compute custom curve */ + + /* XXX COMPUTE THE CURVE, DAMMIT! */ + + for (jack_nframes_t n = 0; n < xfade; ++n) { + xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]); + } + } + + if (xfade) { + cerr << "write " << xfade_bytes << " of xfade data to " << fade_position << " .. " << fade_position + xfade_bytes << endl; + if (::pwrite64 (fd, (char *) xfade_buf, xfade_bytes, fade_position) != (off64_t) xfade_bytes) { + error << string_compose(_("FileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg; + return 0; + } + } + + if (fade_in && nofade) { + cerr << "write " << nofade_bytes << " of postfade IN data to " << file_pos + xfade_bytes << " .. " + << file_pos + xfade_bytes + nofade_bytes << endl; + if (::pwrite64 (fd, (char *) (data + xfade), nofade_bytes, file_pos + xfade_bytes) != (off64_t) nofade_bytes) { + error << string_compose(_("FileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg; + return 0; + } + } return cnt; } @@ -208,6 +241,8 @@ DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int dir) jack_nframes_t DestructiveFileSource::write (Sample* data, jack_nframes_t cnt) { + cerr << _name << ": write " << cnt << " to " << file_pos << " start ? " << _capture_start << " end ? " << _capture_end << endl; + { LockMonitor lm (_lock, __LINE__, __FILE__); @@ -216,11 +251,21 @@ DestructiveFileSource::write (Sample* data, jack_nframes_t cnt) if (_capture_start) { _capture_start = false; + _capture_end = false; + + /* move to the correct location place */ + file_pos = data_offset + (capture_start_frame * sizeof (Sample)); + + cerr << "First byte of capture will be at " << file_pos << endl; + if (crossfade (data, cnt, 1) != cnt) { return 0; } + } else if (_capture_end) { + _capture_start = false; _capture_end = false; + if (crossfade (data, cnt, 0) != cnt) { return 0; } @@ -231,13 +276,15 @@ DestructiveFileSource::write (Sample* data, jack_nframes_t cnt) } } - oldlen = file_pos; + oldlen = _length; if (file_pos + cnt > _length) { _length += cnt; } _write_data_count = byte_cnt; file_pos += byte_cnt; + cerr << "at end of write, file_pos = " << file_pos << endl; + if (_build_peakfiles) { PeakBuildRecord *pbr = 0; @@ -269,3 +316,8 @@ DestructiveFileSource::write (Sample* data, jack_nframes_t cnt) return cnt; } +jack_nframes_t +DestructiveFileSource::last_capture_start_frame () const +{ + return capture_start_frame; +} diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc index 09f9fcdd9d..154e085858 100644 --- a/libs/ardour/diskstream.cc +++ b/libs/ardour/diskstream.cc @@ -614,6 +614,13 @@ DiskStream::check_record_status (jack_nframes_t transport_frame, jack_nframes_t } + if (_flags & Recordable) { + cerr << "START RECORD @ " << capture_start_frame << " = " << capture_start_frame * sizeof (Sample) << endl; + for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { + (*chan).write_source->mark_capture_start (capture_start_frame); + } + } + } else if (!record_enabled() || !can_record) { /* stop recording */ @@ -1060,11 +1067,8 @@ DiskStream::seek (jack_nframes_t frame, bool complete_refill) for (n = 0, chan = channels.begin(); chan != channels.end(); ++chan, ++n) { (*chan).playback_buf->reset (); (*chan).capture_buf->reset (); - if (destructive()) { - DestructiveFileSource* dfs = dynamic_cast ((*chan).write_source); - if (dfs) { - dfs->seek (frame); - } + if ((*chan).write_source) { + (*chan).write_source->seek (frame); } } @@ -1616,7 +1620,7 @@ DiskStream::transport_stopped (struct tm& when, time_t twhen, bool abort_capture */ try { - region = new AudioRegion (srcs, 0, total_capture, + region = new AudioRegion (srcs, channels[0].write_source->last_capture_start_frame(), total_capture, region_name_from_path (channels[0].write_source->name()), 0, AudioRegion::Flag (AudioRegion::DefaultFlags|AudioRegion::Automatic|AudioRegion::WholeFile)); @@ -1635,7 +1639,7 @@ DiskStream::transport_stopped (struct tm& when, time_t twhen, bool abort_capture _session.add_undo (_playlist->get_memento()); _playlist->freeze (); - for (buffer_position = 0, ci = capture_info.begin(); ci != capture_info.end(); ++ci) { + for (buffer_position = channels[0].write_source->last_capture_start_frame(), ci = capture_info.begin(); ci != capture_info.end(); ++ci) { string region_name; _session.region_name (region_name, _name, false); @@ -1683,6 +1687,13 @@ DiskStream::finish_capture (bool rec_monitors_input) { was_recording = false; + if (_flags & Recordable) { + cerr << "STOP CAPTURE\n"; + for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { + (*chan).write_source->mark_capture_end (); + } + } + if (capture_captured == 0) { return; } diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 1a79b9f81e..b329c16cc6 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -1320,6 +1320,10 @@ Session::maybe_enable_record () { atomic_set (&_record_status, Enabled); + /* XXX this save should really happen in another thread. its needed so that + pending capture state can be recovered if we crash. + */ + save_state ("", true); if (_transport_speed) { diff --git a/libs/gtkmm2ext/gtk_ui.cc b/libs/gtkmm2ext/gtk_ui.cc index 747d4be0cd..1a46e1b900 100644 --- a/libs/gtkmm2ext/gtk_ui.cc +++ b/libs/gtkmm2ext/gtk_ui.cc @@ -595,7 +595,7 @@ UI::send_request (Request *req) abort (); } - cerr << "thread " << pthread_self() << " sent request " << req << " type = " << req->type << endl; + // cerr << "thread " << pthread_self() << " sent request " << req << " type = " << req->type << endl; rbuf->increment_write_ptr (1); write (signal_pipe[1], &c, 1); }