#include "pbd/xml++.h"
#include "pbd/memento_command.h"
#include "pbd/enumwriter.h"
+#include "pbd/stateful_diff_command.h"
#include "ardour/ardour.h"
#include "ardour/audioengine.h"
+#include "ardour/butler.h"
#include "ardour/configuration.h"
#include "ardour/cycle_timer.h"
+#include "ardour/debug.h"
#include "ardour/io.h"
#include "ardour/midi_diskstream.h"
#include "ardour/midi_playlist.h"
#include "ardour/session.h"
#include "ardour/smf_source.h"
#include "ardour/utils.h"
+#include "ardour/session_playlists.h"
+#include "ardour/route.h"
#include "midi++/types.h"
in_set_state = true;
- init(flag);
+ init ();
use_new_playlist ();
in_set_state = false;
, _frames_read_from_ringbuffer(0)
{
in_set_state = true;
- init (Recordable);
+ init ();
if (set_state (node, Stateful::loading_state_version)) {
in_set_state = false;
}
void
-MidiDiskstream::init (Diskstream::Flag f)
+MidiDiskstream::init ()
{
- Diskstream::init(f);
-
/* there are no channels at this point, so these
two calls just get speed_buffer_size and wrap_buffer
size setup without duplicating their code.
set_block_size (_session.get_block_size());
allocate_temporary_buffers ();
- const size_t size = _session.midi_diskstream_buffer_size();
+ const size_t size = _session.butler()->midi_diskstream_buffer_size();
_playback_buf = new MidiRingBuffer<nframes_t>(size);
_capture_buf = new MidiRingBuffer<nframes_t>(size);
{
boost::shared_ptr<MidiPlaylist> playlist;
- if ((playlist = boost::dynamic_pointer_cast<MidiPlaylist> (_session.playlist_by_name (name))) == 0) {
+ if ((playlist = boost::dynamic_pointer_cast<MidiPlaylist> (_session.playlists->by_name (name))) == 0) {
playlist = boost::dynamic_pointer_cast<MidiPlaylist> (PlaylistFactory::create (DataType::MIDI, _session, name));
}
#endif
int
-MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input)
+MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input, bool& need_butler)
{
int ret = -1;
nframes_t rec_offset = 0;
bool nominally_recording;
bool re = record_enabled ();
- /* if we've already processed the frames corresponding to this call,
- just return. this allows multiple routes that are taking input
- from this diskstream to call our ::process() method, but have
- this stuff only happen once. more commonly, it allows both
- the AudioTrack that is using this AudioDiskstream *and* the Session
- to call process() without problems.
- */
-
- if (_processed) {
- return 0;
- }
-
- commit_should_unlock = false;
+ playback_distance = 0;
check_record_status (transport_frame, nframes, can_record);
nominally_recording = (can_record && re);
if (nframes == 0) {
- _processed = true;
return 0;
}
- /* This lock is held until the end of ::commit, so these two functions
- must always be called as a pair. The only exception is if this function
- returns a non-zero value, in which case, ::commit should not be called.
- */
+ Glib::Mutex::Lock sm (state_lock, Glib::TRY_LOCK);
- // If we can't take the state lock return.
- if (!state_lock.trylock()) {
+ if (!sm.locked()) {
return 1;
}
- commit_should_unlock = true;
+
adjust_capture_position = 0;
if (nominally_recording || (_session.get_record_enabled() && _session.config.get_punch_in())) {
ret = 0;
- _processed = true;
-
- if (ret) {
-
- /* we're exiting with failure, so ::commit will not
- be called. unlock the state lock.
- */
-
- commit_should_unlock = false;
- state_lock.unlock();
- }
+ if (commit (nframes)) {
+ need_butler = true;
+ }
return ret;
}
" = " << frames_written - frames_read
<< " + " << nframes << " < " << midi_readahead << " = " << need_butler << ")" << endl;*/
- if (commit_should_unlock) {
- state_lock.unlock();
- }
-
- _processed = false;
-
return need_butler;
}
{
/* called from audio thread, so we can use the read ptr and playback sample as we wish */
- pending_overwrite = yn;
+ _pending_overwrite = yn;
overwrite_frame = playback_sample;
}
{
//read(overwrite_frame, disk_io_chunk_frames, false);
overwrite_queued = false;
- pending_overwrite = false;
+ _pending_overwrite = false;
return 0;
}
bool reloop = false;
nframes_t loop_end = 0;
nframes_t loop_start = 0;
- nframes_t loop_length = 0;
Location *loc = 0;
if (!reversed) {
+
+ nframes_t loop_length = 0;
+
/* Make the use of a Location atomic for this read operation.
Note: Locations don't get deleted, so all we care about
}
void
-MidiDiskstream::transport_stopped (struct tm& /*when*/, time_t /*twhen*/, bool abort_capture)
+MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen*/, bool abort_capture)
{
- uint32_t buffer_position;
bool more_work = true;
int err = 0;
boost::shared_ptr<MidiRegion> region;
- nframes_t total_capture;
MidiRegion::SourceList srcs;
MidiRegion::SourceList::iterator src;
vector<CaptureInfo*>::iterator ci;
if (_write_source) {
_write_source->mark_for_remove ();
- _write_source->drop_references ();
_write_source.reset();
}
assert(_write_source);
- for (total_capture = 0, ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
+ nframes_t total_capture = 0;
+ for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
total_capture += (*ci)->frames;
}
*/
try {
- boost::shared_ptr<Region> rx (RegionFactory::create (srcs, 0,
- total_capture, whole_file_region_name, 0,
- Region::Flag (Region::DefaultFlags|Region::Automatic|Region::WholeFile)));
+ PropertyList plist;
+
+ plist.add (Properties::name, whole_file_region_name);
+ plist.add (Properties::whole_file, true);
+ plist.add (Properties::automatic, true);
+ plist.add (Properties::start, 0);
+ plist.add (Properties::length, total_capture);
+ plist.add (Properties::layer, 0);
+
+ boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist));
region = boost::dynamic_pointer_cast<MidiRegion> (rx);
region->special_set_position (capture_info.front()->start);
// cerr << _name << ": there are " << capture_info.size() << " capture_info records\n";
- XMLNode &before = _playlist->get_state();
+ _playlist->clear_history ();
_playlist->freeze ();
+ uint32_t buffer_position = 0;
for (buffer_position = 0, ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
string region_name;
- _session.region_name (region_name, _write_source->name(), false);
+ RegionFactory::region_name (region_name, _write_source->name(), false);
// cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add a region\n";
try {
- boost::shared_ptr<Region> rx (RegionFactory::create (srcs, buffer_position, (*ci)->frames, region_name));
+ PropertyList plist;
+
+ plist.add (Properties::start, buffer_position);
+ plist.add (Properties::length, (*ci)->frames);
+ plist.add (Properties::name, region_name);
+
+ boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist));
region = boost::dynamic_pointer_cast<MidiRegion> (rx);
}
continue; /* XXX is this OK? */
}
- region->GoingAway.connect (bind (mem_fun (*this, &Diskstream::remove_region_from_last_capture), boost::weak_ptr<Region>(region)));
+ region->DropReferences.connect_same_thread (*this, boost::bind (&Diskstream::remove_region_from_last_capture, this, boost::weak_ptr<Region>(region)));
_last_capture_regions.push_back (region);
}
_playlist->thaw ();
- XMLNode &after = _playlist->get_state();
- _session.add_command (new MementoCommand<Playlist>(*_playlist, &before, &after));
+ _session.add_command (new StatefulDiffCommand(_playlist));
}
delete *ci;
}
+ if (_playlist) {
+ midi_playlist()->clear_note_trackers ();
+ }
+
capture_info.clear ();
capture_start_frame = 0;
}
assert(!destructive());
- if (yn && _source_port == 0) {
-
- /* pick up connections not initiated *from* the IO object
- we're associated with.
- */
-
- get_input_sources ();
- }
-
/* yes, i know that this not proof against race conditions, but its
good enough. i think.
*/
XMLNode&
MidiDiskstream::get_state ()
{
- XMLNode* node = new XMLNode ("MidiDiskstream");
+ XMLNode* node = new XMLNode ("Diskstream");
char buf[64];
LocaleGuard lg (X_("POSIX"));
if (_session.config.get_punch_in() && ((pi = _session.locations()->auto_punch_location()) != 0)) {
snprintf (buf, sizeof (buf), "%" PRId64, pi->start());
} else {
- snprintf (buf, sizeof (buf), "%" PRIu32, _session.transport_frame());
+ snprintf (buf, sizeof (buf), "%" PRId64, _session.transport_frame());
}
cs_child->add_property (X_("at"), buf);
const XMLProperty* prop;
XMLNodeList nlist = node.children();
XMLNodeIterator niter;
- uint32_t nchans = 1;
XMLNode* capture_pending_node = 0;
LocaleGuard lg (X_("POSIX"));
set_channel_mode(channel_mode, channel_mask);
- if ((prop = node.property ("channels")) != 0) {
- nchans = atoi (prop->value().c_str());
- }
-
if ((prop = node.property ("playlist")) == 0) {
return -1;
}
}
if (!had_playlist) {
- _playlist->set_orig_diskstream_id (_id);
+ _playlist->set_orig_diskstream_id (id());
}
if (capture_pending_node) {
if (_write_source) {
if (_write_source->is_empty ()) {
+ /* remove any region that is using this empty source; they can result when MIDI recordings
+ are made, but no MIDI data is received.
+ */
+ _playlist->remove_region_by_source (_write_source);
_write_source->mark_for_remove ();
+ _write_source->drop_references ();
_write_source.reset();
} else {
_write_source.reset();
}
try {
- _write_source = boost::dynamic_pointer_cast<SMFSource>(_session.create_midi_source_for_session (*this));
+ _write_source = boost::dynamic_pointer_cast<SMFSource>(_session.create_midi_source_for_session (name ()));
if (!_write_source) {
throw failed_constructor();
}
MidiDiskstream::rename_write_sources ()
{
if (_write_source != 0) {
- _write_source->set_source_name (_name, destructive());
+ _write_source->set_source_name (_name.val(), destructive());
/* XXX what to do if this fails ? */
}
return 0;
// Translates stamps to be relative to start
- _playback_buf->read(dst, start, end);
-#if 0
+#ifndef NDEBUG
const size_t events_read = _playback_buf->read(dst, start, end);
- cout << _name << ": MDS events read = " << events_read
- << " start = " << start << " end = " << end
- << " readspace " << _playback_buf->read_space()
- << " writespace " << _playback_buf->write_space() << endl;
+ DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("%1 MDS events read %2 range %3 .. %4 rspace %5 wspace %6\n", _name, events_read, start, end,
+ _playback_buf->read_space(), _playback_buf->write_space()));
+#else
+ _playback_buf->read(dst, start, end);
#endif
gint32 frames_read = end - start;