no more peak building thread; don't print config var stores, but it possible to do it again without another complete recompile

git-svn-id: svn://localhost/ardour2/trunk@1588 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2007-03-14 14:24:14 +00:00
parent 0641df0ccd
commit 29f6f0cf05
11 changed files with 330 additions and 442 deletions

View file

@ -263,10 +263,6 @@ ARDOUR_UI::set_engine (AudioEngine& e)
AudioFileSource::set_build_peakfiles (true);
AudioFileSource::set_build_missing_peakfiles (true);
if (AudioSource::start_peak_thread ()) {
throw failed_constructor();
}
/* set default clock modes */
primary_clock.set_mode (AudioClock::SMPTE);
@ -304,8 +300,6 @@ ARDOUR_UI::~ARDOUR_UI ()
if (add_route_dialog) {
delete add_route_dialog;
}
AudioSource::stop_peak_thread ();
}
gint
@ -1147,8 +1141,6 @@ ARDOUR_UI::remove_last_capture()
void
ARDOUR_UI::transport_record ()
{
cerr << "transport record\n";
if (session) {
switch (session->record_status()) {
case Session::Disabled:

View file

@ -107,6 +107,7 @@ class AudioFileSource : public AudioSource {
bool destructive() const { return (_flags & Destructive); }
virtual bool set_destructive (bool yn) { return false; }
bool can_truncate_peaks() const { return !destructive(); }
Flag flags() const { return _flags; }

View file

@ -76,6 +76,8 @@ const nframes_t frames_per_peak = 256;
virtual void mark_for_remove() = 0;
virtual void mark_streaming_write_completed () {}
virtual bool can_truncate_peaks() const { return true; }
void set_captured_for (string str) { _captured_for = str; }
string captured_for() const { return _captured_for; }
@ -92,9 +94,6 @@ const nframes_t frames_per_peak = 256;
XMLNode& get_state ();
int set_state (const XMLNode&);
static int start_peak_thread ();
static void stop_peak_thread ();
int rename_peakfile (std::string newpath);
void touch_peakfile ();
@ -108,6 +107,9 @@ const nframes_t frames_per_peak = 256;
virtual int setup_peakfile () { return 0; }
int prepare_for_peakfile_writes ();
void done_with_peakfile_writes ();
protected:
static bool _build_missing_peakfiles;
static bool _build_peakfiles;
@ -115,7 +117,6 @@ const nframes_t frames_per_peak = 256;
bool _peaks_built;
mutable Glib::Mutex _lock;
nframes_t _length;
bool next_peak_clear_should_notify;
string peakpath;
string _captured_for;
@ -123,12 +124,11 @@ const nframes_t frames_per_peak = 256;
mutable uint32_t _write_data_count; // modified in write()
int initialize_peakfile (bool newfile, string path);
void build_peaks_from_scratch ();
int do_build_peak (nframes_t, nframes_t);
int build_peaks_from_scratch ();
int compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force);
void truncate_peakfile();
mutable off_t _peak_byte_max; // modified in do_build_peaks()
mutable off_t _peak_byte_max; // modified in compute_and_write_peak()
virtual nframes_t read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const = 0;
virtual nframes_t write_unlocked (Sample *dst, nframes_t cnt) = 0;
@ -137,40 +137,13 @@ const nframes_t frames_per_peak = 256;
void update_length (nframes_t pos, nframes_t cnt);
static pthread_t peak_thread;
static bool have_peak_thread;
static void* peak_thread_work(void*);
static int peak_request_pipe[2];
struct PeakRequest {
enum Type {
Build,
Quit
};
};
static vector<boost::shared_ptr<AudioSource> > pending_peak_sources;
static Glib::Mutex* pending_peak_sources_lock;
static void queue_for_peaks (boost::shared_ptr<AudioSource>, bool notify=true);
static void clear_queue_for_peaks ();
struct PeakBuildRecord {
nframes_t frame;
nframes_t cnt;
PeakBuildRecord (nframes_t f, nframes_t c)
: frame (f), cnt (c) {}
PeakBuildRecord (const PeakBuildRecord& other) {
frame = other.frame;
cnt = other.cnt;
}
};
list<AudioSource::PeakBuildRecord *> pending_peak_builds;
private:
int peakfile;
nframes_t peak_leftover_cnt;
nframes_t peak_leftover_size;
Sample* peak_leftovers;
nframes_t peak_leftover_frame;
bool file_changed (string path);
};

View file

@ -27,10 +27,13 @@ class ConfigVariableBase {
virtual void add_to_node (XMLNode& node) = 0;
virtual bool set_from_node (const XMLNode& node, Owner owner) = 0;
void show_stored_value (const std::string&);
static void set_show_stored_values (bool yn);
protected:
std::string _name;
Owner _owner;
static bool show_stores;
void notify ();
void miss ();
@ -61,7 +64,7 @@ class ConfigVariable : public ConfigVariableBase
void add_to_node (XMLNode& node) {
std::stringstream ss;
ss << value;
cerr << "Config variable " << _name << " stored as " << ss.str() << endl;
show_stored_value (ss.str());
XMLNode* child = new XMLNode ("Option");
child->add_property ("name", _name);
child->add_property ("value", ss.str());

View file

@ -1322,7 +1322,6 @@ AudioDiskstream::do_flush (Session::RunContext context, bool force_flush)
total = vector.len[0] + vector.len[1];
if (total == 0 || (total < disk_io_chunk_frames && !force_flush && was_recording)) {
goto out;
}
@ -1411,9 +1410,9 @@ AudioDiskstream::do_flush (Session::RunContext context, bool force_flush)
disk_io_chunk_frames of data, so arrange for some part
of vector.len[1] to be flushed to disk as well.
*/
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) {
error << string_compose(_("AudioDiskstream %1: cannot write to disk"), _id) << endmsg;
return -1;
@ -1695,13 +1694,16 @@ AudioDiskstream::engage_record_enable ()
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));
}
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);
@ -1715,8 +1717,8 @@ void
AudioDiskstream::disengage_record_enable ()
{
g_atomic_int_set (&_record_enabled, 0);
if (Config->get_monitoring_model() == HardwareMonitoring) {
for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
if (Config->get_monitoring_model() == HardwareMonitoring) {
if ((*chan).source) {
(*chan).source->ensure_monitor_input (false);
}
@ -1725,7 +1727,6 @@ AudioDiskstream::disengage_record_enable ()
capturing_sources.clear ();
RecordEnableChanged (); /* EMIT SIGNAL */
}
XMLNode&
AudioDiskstream::get_state ()
@ -1919,6 +1920,7 @@ AudioDiskstream::use_new_write_source (uint32_t n)
ChannelInfo &chan = channels[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 ();
}

View file

@ -130,7 +130,6 @@ AudioFileSource::init (string pathstr, bool must_exist)
_length = 0;
timeline_position = 0;
next_peak_clear_should_notify = false;
_peaks_built = false;
file_is_new = false;
@ -260,10 +259,7 @@ AudioFileSource::mark_streaming_write_completed ()
Glib::Mutex::Lock lm (_lock);
next_peak_clear_should_notify = true;
if (_peaks_built || pending_peak_builds.empty()) {
_peaks_built = true;
if (_peaks_built) {
PeaksReady (); /* EMIT SIGNAL */
}
}

View file

@ -1281,6 +1281,7 @@ AudioRegion::normalize_to (float target_dB)
boost::shared_ptr<Playlist> pl (playlist());
if (pl) {
cerr << "Send modified\n";
pl->Modified();
}

View file

@ -42,41 +42,33 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
pthread_t AudioSource::peak_thread;
bool AudioSource::have_peak_thread = false;
vector<boost::shared_ptr<AudioSource> > AudioSource::pending_peak_sources;
Glib::Mutex* AudioSource::pending_peak_sources_lock = 0;
int AudioSource::peak_request_pipe[2];
bool AudioSource::_build_missing_peakfiles = false;
bool AudioSource::_build_peakfiles = false;
AudioSource::AudioSource (Session& s, string name)
: Source (s, name)
{
if (pending_peak_sources_lock == 0) {
pending_peak_sources_lock = new Glib::Mutex;
}
_peaks_built = false;
_peak_byte_max = 0;
next_peak_clear_should_notify = true;
peakfile = -1;
_read_data_count = 0;
_write_data_count = 0;
peak_leftover_cnt = 0;
peak_leftover_size = 0;
peak_leftovers = 0;
}
AudioSource::AudioSource (Session& s, const XMLNode& node)
: Source (s, node)
{
if (pending_peak_sources_lock == 0) {
pending_peak_sources_lock = new Glib::Mutex;
}
_peaks_built = false;
_peak_byte_max = 0;
next_peak_clear_should_notify = true;
peakfile = -1;
_read_data_count = 0;
_write_data_count = 0;
peak_leftover_cnt = 0;
peak_leftover_size = 0;
peak_leftovers = 0;
if (set_state (node)) {
throw failed_constructor();
@ -85,6 +77,19 @@ AudioSource::AudioSource (Session& s, const XMLNode& node)
AudioSource::~AudioSource ()
{
/* shouldn't happen but make sure we don't leak file descriptors anyway */
if (peak_leftover_cnt) {
cerr << "AudioSource destroyed with leftover peak data pending" << endl;
}
if (peakfile >= 0) {
::close (peakfile);
}
if (peak_leftovers) {
delete [] peak_leftovers;
}
}
XMLNode&
@ -117,171 +122,6 @@ AudioSource::set_state (const XMLNode& node)
PEAK FILE STUFF
***********************************************************************/
void*
AudioSource::peak_thread_work (void* arg)
{
PBD::ThreadCreated (pthread_self(), X_("Peak"));
struct pollfd pfd[1];
if (pending_peak_sources_lock == 0) {
pending_peak_sources_lock = new Glib::Mutex;
}
Glib::Mutex::Lock lm (*pending_peak_sources_lock);
while (true) {
pfd[0].fd = peak_request_pipe[0];
pfd[0].events = POLLIN|POLLERR|POLLHUP;
pending_peak_sources_lock->unlock ();
if (poll (pfd, 1, -1) < 0) {
if (errno == EINTR) {
pending_peak_sources_lock->lock ();
continue;
}
error << string_compose (_("poll on peak request pipe failed (%1)"),
strerror (errno))
<< endmsg;
break;
}
if (pfd[0].revents & ~POLLIN) {
error << _("Error on peak thread request pipe") << endmsg;
break;
}
if (pfd[0].revents & POLLIN) {
char req;
/* empty the pipe of all current requests */
while (1) {
size_t nread = ::read (peak_request_pipe[0], &req, sizeof (req));
if (nread == 1) {
switch ((PeakRequest::Type) req) {
case PeakRequest::Build:
break;
case PeakRequest::Quit:
pthread_exit_pbd (0);
/*NOTREACHED*/
break;
default:
break;
}
} else if (nread == 0) {
break;
} else if (errno == EAGAIN) {
break;
} else {
fatal << _("Error reading from peak request pipe") << endmsg;
/*NOTREACHED*/
}
}
}
pending_peak_sources_lock->lock ();
while (!pending_peak_sources.empty()) {
boost::shared_ptr<AudioSource> s = pending_peak_sources.front();
pending_peak_sources.erase (pending_peak_sources.begin());
pending_peak_sources_lock->unlock ();
s->build_peaks();
pending_peak_sources_lock->lock ();
}
}
pthread_exit_pbd (0);
/*NOTREACHED*/
return 0;
}
int
AudioSource::start_peak_thread ()
{
if (!_build_peakfiles) {
return 0;
}
if (pipe (peak_request_pipe)) {
error << string_compose(_("Cannot create transport request signal pipe (%1)"), strerror (errno)) << endmsg;
return -1;
}
if (fcntl (peak_request_pipe[0], F_SETFL, O_NONBLOCK)) {
error << string_compose(_("UI: cannot set O_NONBLOCK on peak request pipe (%1)"), strerror (errno)) << endmsg;
return -1;
}
if (fcntl (peak_request_pipe[1], F_SETFL, O_NONBLOCK)) {
error << string_compose(_("UI: cannot set O_NONBLOCK on peak request pipe (%1)"), strerror (errno)) << endmsg;
return -1;
}
if (pthread_create_and_store ("peak file builder", &peak_thread, 0, peak_thread_work, 0)) {
error << _("AudioSource: could not create peak thread") << endmsg;
return -1;
}
have_peak_thread = true;
return 0;
}
void
AudioSource::stop_peak_thread ()
{
if (!have_peak_thread) {
return;
}
void* status;
char c = (char) PeakRequest::Quit;
::write (peak_request_pipe[1], &c, 1);
pthread_join (peak_thread, &status);
}
void
AudioSource::queue_for_peaks (boost::shared_ptr<AudioSource> source, bool notify)
{
if (have_peak_thread) {
Glib::Mutex::Lock lm (*pending_peak_sources_lock);
source->next_peak_clear_should_notify = notify;
if (find (pending_peak_sources.begin(),
pending_peak_sources.end(),
source) == pending_peak_sources.end()) {
pending_peak_sources.push_back (source);
}
char c = (char) PeakRequest::Build;
::write (peak_request_pipe[1], &c, 1);
}
}
void AudioSource::clear_queue_for_peaks ()
{
/* this is done to cancel a group of running peak builds */
if (have_peak_thread) {
Glib::Mutex::Lock lm (*pending_peak_sources_lock);
pending_peak_sources.clear ();
}
}
bool
AudioSource::peaks_ready (sigc::slot<void> the_slot, sigc::connection& conn) const
{
@ -430,7 +270,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
int ret = -1;
PeakData* staging = 0;
Sample* raw_staging = 0;
int peakfile = -1;
int _peakfile = -1;
expected_peaks = (cnt / (double) frames_per_peak);
scale = npeaks/expected_peaks;
@ -491,7 +331,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
/* open, read, close */
if ((peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) {
if ((_peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) {
error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
return -1;
}
@ -500,8 +340,8 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
cerr << "DIRECT PEAKS\n";
#endif
nread = ::pread (peakfile, peaks, sizeof (PeakData)* npeaks, first_peak_byte);
close (peakfile);
nread = ::pread (_peakfile, peaks, sizeof (PeakData)* npeaks, first_peak_byte);
close (_peakfile);
if (nread != sizeof (PeakData) * npeaks) {
cerr << "AudioSource["
@ -565,7 +405,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
/* open ... close during out: handling */
if ((peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) {
if ((_peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) {
error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
return 0;
}
@ -582,10 +422,10 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
cerr << "read " << sizeof (PeakData) * to_read << " from peakfile @ " << start_byte << endl;
#endif
if ((nread = ::pread (peakfile, staging, sizeof (PeakData) * to_read, start_byte))
if ((nread = ::pread (_peakfile, staging, sizeof (PeakData) * to_read, start_byte))
!= sizeof (PeakData) * to_read) {
off_t fend = lseek (peakfile, 0, SEEK_END);
off_t fend = lseek (_peakfile, 0, SEEK_END);
cerr << "AudioSource["
<< _name
@ -671,13 +511,21 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
to_read = min (chunksize, (_length - current_frame));
if (to_read == 0) {
/* XXX ARGH .. out by one error ... need to figure out why this happens
and fix it rather than do this band-aid move.
*/
zero_fill = npeaks - nvisual_peaks;
break;
}
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)
error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3 of %4 (%5)"),
_name, to_read, current_frame, _length, strerror (errno))
<< endmsg;
goto out;
}
i = 0;
}
@ -707,8 +555,8 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
}
out:
if (peakfile >= 0) {
close (peakfile);
if (_peakfile >= 0) {
close (_peakfile);
}
if (staging) {
@ -729,191 +577,290 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
#undef DEBUG_PEAK_BUILD
int
AudioSource::build_peaks ()
AudioSource::build_peaks_from_scratch ()
{
vector<PeakBuildRecord*> built;
int status = -1;
bool pr_signal = false;
list<PeakBuildRecord*> copy;
nframes_t current_frame;
nframes_t cnt;
Sample buf[frames_per_peak];
nframes_t frames_read;
nframes_t frames_to_read;
int ret = -1;
{
Glib::Mutex::Lock lm (_lock);
copy = pending_peak_builds;
pending_peak_builds.clear ();
}
#ifdef DEBUG_PEAK_BUILD
cerr << "build peaks with " << copy.size() << " requests pending\n";
#endif
/* hold lock while building peaks */
for (list<PeakBuildRecord *>::iterator i = copy.begin(); i != copy.end(); ++i) {
Glib::Mutex::Lock lp (_lock);
if ((status = do_build_peak ((*i)->frame, (*i)->cnt)) != 0) {
unlink (peakpath.c_str());
break;
if (prepare_for_peakfile_writes ()) {
return -1;
}
built.push_back (new PeakBuildRecord (*(*i)));
delete *i;
}
{
Glib::Mutex::Lock lm (_lock);
if (status == 0) {
_peaks_built = true;
current_frame = 0;
cnt = _length;
_peaks_built = false;
while (cnt) {
if (next_peak_clear_should_notify) {
next_peak_clear_should_notify = false;
pr_signal = true;
frames_to_read = min (frames_per_peak, cnt);
if ((frames_read = read_unlocked (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;
done_with_peakfile_writes ();
goto out;
}
}
}
if (status == 0) {
for (vector<PeakBuildRecord *>::iterator i = built.begin(); i != built.end(); ++i) {
PeakRangeReady ((*i)->frame, (*i)->cnt); /* EMIT SIGNAL */
delete *i;
if (compute_and_write_peaks (buf, current_frame, frames_read, true)) {
break;
}
current_frame += frames_read;
cnt -= frames_read;
}
if (pr_signal) {
if (cnt == 0) {
/* success */
truncate_peakfile();
PeaksReady (); /* EMIT SIGNAL */
}
_peaks_built = true;
}
done_with_peakfile_writes ();
}
return status;
/* lock no longer held, safe to signal */
if (_peaks_built) {
PeaksReady (); /* EMIT SIGNAL */
ret = 0;
}
out:
if (ret) {
unlink (peakpath.c_str());
}
return ret;
}
int
AudioSource::do_build_peak (nframes_t first_frame, nframes_t cnt)
AudioSource::prepare_for_peakfile_writes ()
{
nframes_t current_frame;
Sample buf[frames_per_peak];
Sample xmin, xmax;
uint32_t peaki;
PeakData* peakbuf;
nframes_t frames_read;
nframes_t frames_to_read;
off_t first_peak_byte;
int peakfile = -1;
int ret = -1;
off_t target_length;
off_t endpos;
#ifdef DEBUG_PEAK_BUILD
cerr << pthread_self() << ": " << _name << ": building peaks for " << first_frame << " to " << first_frame + cnt - 1 << endl;
#endif
first_peak_byte = (first_frame / frames_per_peak) * sizeof (PeakData);
#ifdef DEBUG_PEAK_BUILD
cerr << "seeking to " << first_peak_byte << " before writing new peak data\n";
#endif
current_frame = first_frame;
peakbuf = new PeakData[(cnt/frames_per_peak)+1];
peaki = 0;
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;
}
while (cnt) {
return 0;
}
frames_to_read = min (frames_per_peak, cnt);
void
AudioSource::done_with_peakfile_writes ()
{
if (peak_leftover_cnt) {
compute_and_write_peaks (0, 0, 0, true);
}
/* lock for every read */
if (peakfile >= 0) {
close (peakfile);
peakfile = -1;
}
}
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;
static bool wrote_xmax = false;
int
AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force)
{
Sample* buf2 = 0;
Sample xmin, xmax;
nframes_t to_do;
uint32_t peaks_computed;
PeakData* peakbuf;
int ret = -1;
nframes_t current_frame;
nframes_t frames_done;
const size_t blocksize = (128 * 1024);
off_t first_peak_byte;
if (peakfile < 0) {
prepare_for_peakfile_writes ();
}
restart:
if (peak_leftover_cnt) {
if (first_frame != peak_leftover_frame + peak_leftover_cnt) {
cerr << "seek, flush out " << peak_leftover_cnt << endl;
/* uh-oh, ::seek() since the last ::compute_and_write_peaks(),
and we have leftovers. flush a single peak (since the leftovers
never represent more than that, and restart.
*/
PeakData x;
x.min = peak_leftovers[0];
x.max = peak_leftovers[0];
for (nframes_t n = 1; n < peak_leftover_cnt; ++n) {
x.max = max (x.max, peak_leftovers[n]);
x.min = min (x.min, peak_leftovers[n]);
}
off_t byte = (peak_leftover_frame / frames_per_peak) * sizeof (PeakData);
if (::pwrite (peakfile, &x, sizeof (PeakData), byte) != sizeof (PeakData)) {
error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
goto out;
}
_peak_byte_max = max (_peak_byte_max, (off_t) (byte + sizeof(PeakData)));
PeakRangeReady (peak_leftover_frame, peak_leftover_cnt); /* EMIT SIGNAL */
PeaksReady (); /* EMIT SIGNAL */
/* left overs are done */
peak_leftover_cnt = 0;
goto restart;
}
/* else ... had leftovers, but they immediately preceed the new data, so just
merge them and compute.
*/
/* make a new contiguous buffer containing leftovers and the new stuff */
to_do = cnt + peak_leftover_cnt;
buf2 = new Sample[to_do];
/* the remnants */
memcpy (buf2, peak_leftovers, peak_leftover_cnt * sizeof (Sample));
/* the new stuff */
memcpy (buf2+peak_leftover_cnt, buf, cnt * sizeof (Sample));
/* no more leftovers */
peak_leftover_cnt = 0;
/* use the temporary buffer */
buf = buf2;
/* make sure that when we write into the peakfile, we startup where we left off */
first_frame = peak_leftover_frame;
} else {
to_do = cnt;
}
peakbuf = new PeakData[(to_do/frames_per_peak)+1];
peaks_computed = 0;
current_frame = first_frame;
frames_done = 0;
while (to_do) {
/* if some frames were passed in (i.e. we're not flushing leftovers)
and there are less than frames_per_peak to do, save them till
next time
*/
if (force && (to_do < frames_per_peak)) {
/* keep the left overs around for next time */
cerr << "save " << to_do << " leftovers\n";
if (peak_leftover_size < to_do) {
delete [] peak_leftovers;
peak_leftovers = new Sample[to_do];
peak_leftover_size = to_do;
}
memcpy (peak_leftovers, buf, to_do * sizeof (Sample));
peak_leftover_cnt = to_do;
peak_leftover_frame = current_frame;
/* done for now */
break;
}
nframes_t this_time = min (frames_per_peak, to_do);
xmin = buf[0];
xmax = buf[0];
for (nframes_t n = 1; n < frames_read; ++n) {
for (nframes_t n = 1; n < this_time; ++n) {
xmax = max (xmax, buf[n]);
xmin = min (xmin, buf[n]);
// if (current_frame < frames_read) {
// cerr << "sample = " << buf[n] << " max = " << xmax << " min = " << xmin << " max of 2 = " << max (xmax, buf[n]) << endl;
// }
}
peakbuf[peaki].max = xmax;
peakbuf[peaki].min = xmin;
peaki++;
current_frame += frames_read;
cnt -= frames_read;
}
#define BLOCKSIZE (128 * 1024)
/* on some filesystems (ext3, at least) this helps to reduce fragmentation of
the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
it does not cause single-extent allocation even for peakfiles of
less than BLOCKSIZE bytes. only call ftruncate if we'll make the file larger.
*/
endpos = lseek (peakfile, 0, SEEK_END);
target_length = BLOCKSIZE * ((first_peak_byte + BLOCKSIZE + 1) / BLOCKSIZE);
if (endpos < target_length) {
// XXX - we really shouldn't be doing this for destructive source peaks
ftruncate (peakfile, target_length);
//cerr << "do build TRUNC: " << peakpath << " " << target_length << endl;
peakbuf[peaks_computed].max = xmax;
peakbuf[peaks_computed].min = xmin;
/* error doesn't actually matter though, so continue on without testing */
peaks_computed++;
buf += this_time;
to_do -= this_time;
frames_done += this_time;
current_frame += this_time;
}
first_peak_byte = (first_frame / frames_per_peak) * sizeof (PeakData);
if (can_truncate_peaks()) {
/* on some filesystems (ext3, at least) this helps to reduce fragmentation of
the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
it does not cause single-extent allocation even for peakfiles of
less than BLOCKSIZE bytes. only call ftruncate if we'll make the file larger.
*/
off_t endpos = lseek (peakfile, 0, SEEK_END);
off_t target_length = blocksize * ((first_peak_byte + blocksize + 1) / blocksize);
if (endpos < target_length) {
ftruncate (peakfile, target_length);
/* error doesn't actually matter though, so continue on without testing */
}
}
if (::pwrite (peakfile, peakbuf, sizeof (PeakData) * peaki, first_peak_byte) != (ssize_t) (sizeof (PeakData) * peaki)) {
if (::pwrite (peakfile, peakbuf, sizeof (PeakData) * peaks_computed, first_peak_byte) != (ssize_t) (sizeof (PeakData) * peaks_computed)) {
error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
goto out;
}
_peak_byte_max = max(_peak_byte_max, (off_t) (first_peak_byte + sizeof(PeakData)*peaki));
_peak_byte_max = max (_peak_byte_max, (off_t) (first_peak_byte + sizeof(PeakData)*peaks_computed));
if (frames_done) {
PeakRangeReady (first_frame, frames_done); /* EMIT SIGNAL */
PeaksReady (); /* EMIT SIGNAL */
}
ret = 0;
out:
delete [] peakbuf;
if (peakfile >= 0) {
close (peakfile);
if (buf2) {
delete [] buf2;
}
return ret;
}
void
AudioSource::build_peaks_from_scratch ()
{
Glib::Mutex::Lock lp (_lock);
next_peak_clear_should_notify = true;
pending_peak_builds.push_back (new PeakBuildRecord (0, _length));
queue_for_peaks (shared_from_this(), true);
}
void
AudioSource::truncate_peakfile ()
{
int peakfile = -1;
if (peakfile < 0) {
error << string_compose (_("programming error: %1"), "AudioSource::truncate_peakfile() called without open peakfile descriptor")
<< endmsg;
return;
}
/* truncate the peakfile down to its natural length if necessary */
if ((peakfile = ::open (peakpath.c_str(), O_RDWR)) >= 0) {
off_t end = lseek (peakfile, 0, SEEK_END);
if (end > _peak_byte_max) {
ftruncate(peakfile, _peak_byte_max);
//cerr << "truncated " << peakpath << " to " << _peak_byte_max << " bytes" << endl;
}
else {
//cerr << "NOT truncated " << peakpath << " to " << _peak_byte_max << " end " << end << endl;
}
close (peakfile);
off_t end = lseek (peakfile, 0, SEEK_END);
if (end > _peak_byte_max) {
ftruncate (peakfile, _peak_byte_max);
}
}

View file

@ -316,6 +316,22 @@ Configuration::map_parameters (sigc::slot<void,const char*> theSlot)
#undef CONFIG_VARIABLE_SPECIAL
}
bool ConfigVariableBase::show_stores = false;
void
ConfigVariableBase::set_show_stored_values (bool yn)
{
show_stores = yn;
}
void
ConfigVariableBase::show_stored_value (const string& str)
{
if (show_stores) {
cerr << "Config variable " << _name << " stored as " << str << endl;
}
}
void
ConfigVariableBase::notify ()
{
@ -328,3 +344,4 @@ ConfigVariableBase::miss ()
// placeholder for any debugging desired when a config variable
// is set but to the same value as it already has
}

View file

@ -3867,6 +3867,10 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
buffers.push_back (b);
}
for (vector<boost::shared_ptr<AudioSource> >::iterator src=srcs.begin(); src != srcs.end(); ++src) {
(*src)->prepare_for_peakfile_writes ();
}
while (to_do && !itt.cancel) {
this_chunk = min (to_do, chunk_size);
@ -3909,15 +3913,6 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
}
}
/* build peakfile for new source */
for (vector<boost::shared_ptr<AudioSource> >::iterator src=srcs.begin(); src != srcs.end(); ++src) {
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
if (afs) {
afs->build_peaks ();
}
}
/* construct a region to represent the bounced material */
boost::shared_ptr<Region> aregion = RegionFactory::create (srcs, 0, srcs.front()->length(),
@ -3937,6 +3932,11 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
(*src)->drop_references ();
}
} else {
for (vector<boost::shared_ptr<AudioSource> >::iterator src = srcs.begin(); src != srcs.end(); ++src) {
(*src)->done_with_peakfile_writes ();
}
}
for (vector<Sample*>::iterator i = buffers.begin(); i != buffers.end(); ++i) {

View file

@ -396,28 +396,7 @@ SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
update_length (oldlen, cnt);
if (_build_peakfiles) {
PeakBuildRecord *pbr = 0;
if (pending_peak_builds.size()) {
pbr = pending_peak_builds.back();
}
if (pbr && pbr->frame + pbr->cnt == oldlen) {
/* the last PBR extended to the start of the current write,
so just extend it again.
*/
pbr->cnt += cnt;
} else {
pending_peak_builds.push_back (new PeakBuildRecord (oldlen, cnt));
}
_peaks_built = false;
}
if (_build_peakfiles) {
queue_for_peaks (shared_from_this (), false);
compute_and_write_peaks (data, frame_pos, cnt, false);
}
_write_data_count = cnt;
@ -507,32 +486,12 @@ SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
old_file_pos = file_pos;
update_length (file_pos, cnt);
if (_build_peakfiles) {
compute_and_write_peaks (data, file_pos, cnt, false);
}
file_pos += cnt;
if (_build_peakfiles) {
PeakBuildRecord *pbr = 0;
if (pending_peak_builds.size()) {
pbr = pending_peak_builds.back();
}
if (pbr && pbr->frame + pbr->cnt == old_file_pos) {
/* the last PBR extended to the start of the current write,
so just extend it again.
*/
pbr->cnt += cnt;
} else {
pending_peak_builds.push_back (new PeakBuildRecord (old_file_pos, cnt));
}
_peaks_built = false;
}
if (_build_peakfiles) {
queue_for_peaks (shared_from_this (), true);
}
return cnt;
}
@ -627,9 +586,6 @@ SndFileSource::set_header_timeline_position ()
delete _broadcast_info;
_broadcast_info = 0;
}
}
nframes_t