#include "pbd/memento_command.h"
#include "pbd/enumwriter.h"
#include "pbd/stateful_diff_command.h"
+#include "pbd/stacktrace.h"
#include "ardour/ardour.h"
#include "ardour/audioengine.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 ();
+ use_new_write_source (0);
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;
throw failed_constructor();
}
- in_set_state = false;
+ use_new_write_source (0);
- if (destructive()) {
- use_destructive_playlist ();
- }
+ 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.
/* implicit unlock */
}
- /* reset capture files */
-
- reset_write_sources (false);
+ /* unlike with audio, there is never any need to reset write sources
+ based on input configuration changes because ... a MIDI track
+ has just 1 MIDI port as input, always.
+ */
/* now refill channel buffers */
o << trace_prefix
<< "Channel "
<< (msg[0]&0xF)+1
- << " Program PropertyChange ProgNum "
+ << " Program Change ProgNum "
<< (int) msg[1]
<< endl;
break;
}
- if (can_record && !_last_capture_regions.empty()) {
- _last_capture_regions.clear ();
+ if (can_record && !_last_capture_sources.empty()) {
+ _last_capture_sources.clear ();
}
if (nominally_recording || rec_nframes) {
{
/* 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;
}
}
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)
{
bool more_work = true;
int err = 0;
if (_write_source) {
_write_source->mark_for_remove ();
- _write_source->drop_references ();
_write_source.reset();
}
total_capture += (*ci)->frames;
}
- /* figure out the name for this take */
-
- srcs.push_back (_write_source);
- _write_source->set_timeline_position (capture_info.front()->start);
- _write_source->set_captured_for (_name);
-
- string whole_file_region_name;
- whole_file_region_name = region_name_from_path (_write_source->name(), true);
-
- /* Register a new region with the Session that
- describes the entire source. Do this first
- so that any sub-regions will obviously be
- children of this one (later!)
- */
-
- try {
- 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);
- }
-
-
- catch (failed_constructor& err) {
- error << string_compose(_("%1: could not create region for complete midi file"), _name) << endmsg;
- /* XXX what now? */
- }
-
- _last_capture_regions.push_back (region);
-
- // cerr << _name << ": there are " << capture_info.size() << " capture_info records\n";
-
- _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;
-
- 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 {
- PropertyList plist;
+ if (_write_source->length (capture_info.front()->start) != 0) {
+
+ /* phew, we have data */
+
+ /* figure out the name for this take */
+
+ srcs.push_back (_write_source);
+
+ _write_source->set_timeline_position (capture_info.front()->start);
+ _write_source->set_captured_for (_name);
+
+ /* flush to disk: this step differs from the audio path,
+ where all the data is already on disk.
+ */
+
+ _write_source->mark_streaming_write_completed ();
+
+ /* we will want to be able to keep (over)writing the source
+ but we don't want it to be removable. this also differs
+ from the audio situation, where the source at this point
+ must be considered immutable
+ */
+
+ _write_source->mark_nonremovable ();
+
+ string whole_file_region_name;
+ whole_file_region_name = region_name_from_path (_write_source->name(), true);
+
+ /* Register a new region with the Session that
+ describes the entire source. Do this first
+ so that any sub-regions will obviously be
+ children of this one (later!)
+ */
+
+ try {
+ 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);
+ }
+
+
+ catch (failed_constructor& err) {
+ error << string_compose(_("%1: could not create region for complete midi file"), _name) << endmsg;
+ /* XXX what now? */
+ }
+
+ _last_capture_sources.insert (_last_capture_sources.end(), srcs.begin(), srcs.end());
+
+ _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;
+
+ 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 {
+ PropertyList plist;
- plist.add (Properties::start, buffer_position);
- plist.add (Properties::length, (*ci)->frames);
- plist.add (Properties::name, region_name);
+ 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);
- }
+ boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist));
+ region = boost::dynamic_pointer_cast<MidiRegion> (rx);
+ }
- catch (failed_constructor& err) {
- error << _("MidiDiskstream: could not create region for captured midi!") << endmsg;
- continue; /* XXX is this OK? */
- }
+ catch (failed_constructor& err) {
+ error << _("MidiDiskstream: could not create region for captured midi!") << endmsg;
+ continue; /* XXX is this OK? */
+ }
- region->DropReferences.connect_same_thread (*this, boost::bind (&Diskstream::remove_region_from_last_capture, this, boost::weak_ptr<Region>(region)));
+ // cerr << "add new region, buffer position = " << buffer_position << " @ " << (*ci)->start << endl;
- _last_capture_regions.push_back (region);
+ i_am_the_modifier++;
+ _playlist->add_region (region, (*ci)->start);
+ i_am_the_modifier--;
- // cerr << "add new region, buffer position = " << buffer_position << " @ " << (*ci)->start << endl;
+ buffer_position += (*ci)->frames;
+ }
- i_am_the_modifier++;
- _playlist->add_region (region, (*ci)->start);
- i_am_the_modifier--;
-
- buffer_position += (*ci)->frames;
- }
-
- _playlist->thaw ();
- _session.add_command (new StatefulDiffCommand(_playlist));
+ _playlist->thaw ();
+ _session.add_command (new StatefulDiffCommand(_playlist));
+ }
+ mark_write_completed = true;
}
- mark_write_completed = true;
-
- reset_write_sources (mark_write_completed);
+ use_new_write_source (0);
for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
delete *ci;
_source_port->request_monitor_input (!(_session.config.get_auto_input() && rolling));
}
- // FIXME: Why is this necessary? Isn't needed for AudioDiskstream...
- if (!_write_source)
- use_new_write_source();
-
_write_source->mark_streaming_midi_write_started (_note_mode, _session.transport_frame());
RecordEnableChanged (); /* EMIT SIGNAL */
XMLNode&
MidiDiskstream::get_state ()
{
- XMLNode* node = new XMLNode ("MidiDiskstream");
+ XMLNode* node = new XMLNode ("Diskstream");
char buf[64];
LocaleGuard lg (X_("POSIX"));
}
if (!had_playlist) {
- _playlist->set_orig_diskstream_id (_id);
+ _playlist->set_orig_diskstream_id (id());
}
if (capture_pending_node) {
in_set_state = false;
- /* make sure this is clear before we do anything else */
-
- // FIXME?
- //_capturing_source = 0;
-
- /* write sources are handled when we handle the input set
- up of the IO that owns this DS (::non_realtime_input_change())
- */
-
- in_set_state = false;
-
return 0;
}
assert(n == 0);
- if (_write_source) {
-
- if (_write_source->is_empty ()) {
- _write_source->mark_for_remove ();
- _write_source.reset();
- } else {
- _write_source.reset();
- }
- }
+ _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 (0, name ()));
if (!_write_source) {
throw failed_constructor();
}
return 0;
}
+list<boost::shared_ptr<Source> >
+MidiDiskstream::steal_write_sources()
+{
+ list<boost::shared_ptr<Source> > ret;
+ ret.push_back (_write_source);
+ reset_write_sources (false);
+ return ret;
+}
+
void
MidiDiskstream::reset_write_sources (bool mark_write_complete, bool /*force*/)
{