mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-10 15:36:24 +01:00
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:
parent
0641df0ccd
commit
29f6f0cf05
11 changed files with 330 additions and 442 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1281,6 +1281,7 @@ AudioRegion::normalize_to (float target_dB)
|
|||
boost::shared_ptr<Playlist> pl (playlist());
|
||||
|
||||
if (pl) {
|
||||
cerr << "Send modified\n";
|
||||
pl->Modified();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue