X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fmidi_diskstream.cc;h=28ee12cc5ae3f574d0c24cf1bf4366a7883096d5;hb=0938a42440cc82ce8d0cb064840c258c863714ab;hp=bfd57573dfd918c7b98c33edcf526c307f28bb16;hpb=f30402d073aeae5d24462416407e73d1e0314e71;p=ardour.git diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index bfd57573df..28ee12cc5a 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -67,25 +67,22 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -nframes_t MidiDiskstream::midi_readahead = 4096; +framecnt_t MidiDiskstream::midi_readahead = 4096; MidiDiskstream::MidiDiskstream (Session &sess, const string &name, Diskstream::Flag flag) : Diskstream(sess, name, flag) , _playback_buf(0) , _capture_buf(0) , _source_port(0) - , _last_flush_frame(0) , _note_mode(Sustained) , _frames_written_to_ringbuffer(0) , _frames_read_from_ringbuffer(0) { - /* prevent any write sources from being created */ - in_set_state = true; init (); use_new_playlist (); - use_new_write_source (0); + use_new_write_source (0); in_set_state = false; @@ -97,7 +94,6 @@ MidiDiskstream::MidiDiskstream (Session& sess, const XMLNode& node) , _playback_buf(0) , _capture_buf(0) , _source_port(0) - , _last_flush_frame(0) , _note_mode(Sustained) , _frames_written_to_ringbuffer(0) , _frames_read_from_ringbuffer(0) @@ -111,7 +107,7 @@ MidiDiskstream::MidiDiskstream (Session& sess, const XMLNode& node) throw failed_constructor(); } - use_new_write_source (0); + use_new_write_source (0); in_set_state = false; } @@ -128,8 +124,8 @@ MidiDiskstream::init () allocate_temporary_buffers (); const size_t size = _session.butler()->midi_diskstream_buffer_size(); - _playback_buf = new MidiRingBuffer(size); - _capture_buf = new MidiRingBuffer(size); + _playback_buf = new MidiRingBuffer(size); + _capture_buf = new MidiRingBuffer(size); _n_channels = ChanCount(DataType::MIDI, 1); @@ -143,12 +139,12 @@ MidiDiskstream::~MidiDiskstream () void -MidiDiskstream::non_realtime_locate (nframes_t position) +MidiDiskstream::non_realtime_locate (framepos_t position) { if (_write_source) { _write_source->set_timeline_position (position); } - seek(position, false); + seek (position, false); } @@ -158,64 +154,55 @@ MidiDiskstream::non_realtime_input_change () { Glib::Mutex::Lock lm (state_lock); - if (input_change_pending == NoChange) { + if (input_change_pending.type == IOChange::NoChange) { return; } - if (input_change_pending & ConfigurationChanged) { - if (_io->n_ports().n_midi() != _n_channels.n_midi()) { - error << "Can not feed IO " << _io->n_ports() - << " with diskstream " << _n_channels << endl; + if (input_change_pending.type & IOChange::ConfigurationChanged) { + uint32_t ni = _io->n_ports().n_midi(); + + if (ni != _n_channels.n_midi()) { + error << string_compose (_("%1: I/O configuration change %4 requested to use %2, but channel setup is %3"), + name(), + _io->n_ports(), + _n_channels, input_change_pending.type) + << endmsg; } - } - get_input_sources (); - set_capture_offset (); + if (ni == 0) { + _source_port = 0; + } else { + _source_port = _io->midi(0); + } + } - if (first_input_change) { - set_align_style (_persistent_alignment_style); - first_input_change = false; - } else { + if (input_change_pending.type & IOChange::ConnectionsChanged) { + set_capture_offset (); set_align_style_from_io (); } - input_change_pending = NoChange; + input_change_pending.type = IOChange::NoChange; /* implicit unlock */ } - /* 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. - */ + /* 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 */ if (speed() != 1.0f || speed() != -1.0f) { - seek ((nframes_t) (_session.transport_frame() * (double) speed())); + seek ((framepos_t) (_session.transport_frame() * (double) speed())); } else { seek (_session.transport_frame()); } - _last_flush_frame = _session.transport_frame(); -} - -void -MidiDiskstream::get_input_sources () -{ - uint32_t ni = _io->n_ports().n_midi(); - - if (ni == 0) { - return; + if (_write_source) { + _write_source->set_last_write_end (_session.transport_frame()); } - - // This is all we do for now at least - assert(ni == 1); - - _source_port = _io->midi(0); - - // do... stuff? } int @@ -304,6 +291,7 @@ MidiDiskstream::use_copy_playlist () int MidiDiskstream::set_destructive (bool yn) { + yn = 0; // stop pedantic gcc complaints about unused parameter assert( ! destructive()); assert( ! yn); return -1; @@ -488,17 +476,17 @@ trace_midi (ostream& o, MIDI::byte *msg, size_t len) #endif int -MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input, bool& need_butler) +MidiDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool can_record, bool& need_butler) { int ret = -1; - nframes_t rec_offset = 0; - nframes_t rec_nframes = 0; + framecnt_t rec_offset = 0; + framecnt_t rec_nframes = 0; bool nominally_recording; bool re = record_enabled (); - playback_distance = 0; + playback_distance = 0; - check_record_status (transport_frame, nframes, can_record); + check_record_status (transport_frame, can_record); nominally_recording = (can_record && re); @@ -506,9 +494,13 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_ return 0; } - Glib::Mutex::Lock sm (state_lock, Glib::TRY_LOCK); + if (_source_port == 0) { + return 1; + } + + Glib::Mutex::Lock sm (state_lock, Glib::TRY_LOCK); - if (!sm.locked()) { + if (!sm.locked()) { return 1; } @@ -520,12 +512,12 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_ calculate_record_range(ot, transport_frame, nframes, rec_nframes, rec_offset); if (rec_nframes && !was_recording) { + _write_source->mark_write_starting_now (); capture_captured = 0; was_recording = true; } } - if (can_record && !_last_capture_sources.empty()) { _last_capture_sources.clear (); } @@ -537,13 +529,42 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_ for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) { const Evoral::MIDIEvent ev(*i, false); assert(ev.buffer()); +#ifndef NDEBUG + if (DEBUG::MidiIO & PBD::debug_bits) { + const uint8_t* __data = ev.buffer(); + DEBUG_STR_DECL(a); + DEBUG_STR_APPEND(a, string_compose ("mididiskstream %1 capture event @ %2 + %3 sz %4 ", this, ev.time(), transport_frame, ev.size())); + for (size_t i=0; i < ev.size(); ++i) { + DEBUG_STR_APPEND(a,hex); + DEBUG_STR_APPEND(a,"0x"); + DEBUG_STR_APPEND(a,(int)__data[i]); + DEBUG_STR_APPEND(a,' '); + } + DEBUG_STR_APPEND(a,'\n'); + DEBUG_TRACE (DEBUG::MidiIO, DEBUG_STR(a).str()); + } +#endif _capture_buf->write(ev.time() + transport_frame, ev.type(), ev.size(), ev.buffer()); } + if (buf.size() != 0) { + /* XXX this needs fixing - realtime new() call for + every time we get MIDI data in a process callback! + */ + + /* Make a copy of this data and emit it for the GUI to see */ + boost::shared_ptr copy (new MidiBuffer (buf.capacity ())); + for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) { + copy->push_back ((*i).time() + transport_frame, (*i).size(), (*i).buffer()); + } + + DataRecorded (copy, _write_source); /* EMIT SIGNAL */ + } + } else { if (was_recording) { - finish_capture (rec_monitors_input); + finish_capture (); } } @@ -566,19 +587,25 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_ playback_distance = nframes; + } else { + + /* XXX: should be doing varispeed stuff here, similar to the code in AudioDiskstream::process */ + + playback_distance = nframes; + } ret = 0; - if (commit (nframes)) { - need_butler = true; - } + if (commit (nframes)) { + need_butler = true; + } return ret; } bool -MidiDiskstream::commit (nframes_t nframes) +MidiDiskstream::commit (framecnt_t nframes) { bool need_butler = false; @@ -612,14 +639,20 @@ MidiDiskstream::set_pending_overwrite (bool yn) /* called from audio thread, so we can use the read ptr and playback sample as we wish */ _pending_overwrite = yn; - overwrite_frame = playback_sample; } int MidiDiskstream::overwrite_existing_buffers () { - //read(overwrite_frame, disk_io_chunk_frames, false); + /* This is safe as long as the butler thread is suspended, which it should be */ + _playback_buf->reset (); + + g_atomic_int_set (&_frames_read_from_ringbuffer, 0); + g_atomic_int_set (&_frames_written_to_ringbuffer, 0); + + read (overwrite_frame, disk_io_chunk_frames, false); + file_frame = overwrite_frame; // it was adjusted by ::read() overwrite_queued = false; _pending_overwrite = false; @@ -627,7 +660,7 @@ MidiDiskstream::overwrite_existing_buffers () } int -MidiDiskstream::seek (nframes_t frame, bool complete_refill) +MidiDiskstream::seek (framepos_t frame, bool complete_refill) { Glib::Mutex::Lock lm (state_lock); int ret = -1; @@ -650,7 +683,7 @@ MidiDiskstream::seek (nframes_t frame, bool complete_refill) } int -MidiDiskstream::can_internal_playback_seek (nframes_t distance) +MidiDiskstream::can_internal_playback_seek (framecnt_t distance) { uint32_t frames_read = g_atomic_int_get(&_frames_read_from_ringbuffer); uint32_t frames_written = g_atomic_int_get(&_frames_written_to_ringbuffer); @@ -658,7 +691,7 @@ MidiDiskstream::can_internal_playback_seek (nframes_t distance) } int -MidiDiskstream::internal_playback_seek (nframes_t distance) +MidiDiskstream::internal_playback_seek (framecnt_t distance) { first_recordable_frame += distance; playback_sample += distance; @@ -668,17 +701,17 @@ MidiDiskstream::internal_playback_seek (nframes_t distance) /** @a start is set to the new frame position (TIME) read up to */ int -MidiDiskstream::read (nframes_t& start, nframes_t dur, bool reversed) +MidiDiskstream::read (framepos_t& start, framecnt_t dur, bool reversed) { - nframes_t this_read = 0; + framecnt_t this_read = 0; bool reloop = false; - nframes_t loop_end = 0; - nframes_t loop_start = 0; + framepos_t loop_end = 0; + framepos_t loop_start = 0; Location *loc = 0; if (!reversed) { - nframes_t loop_length = 0; + framecnt_t loop_length = 0; /* Make the use of a Location atomic for this read operation. @@ -749,10 +782,7 @@ MidiDiskstream::read (nframes_t& start, nframes_t dur, bool reversed) if (reloop) { // Synthesize LoopEvent here, because the next events // written will have non-monotonic timestamps. - _playback_buf->write(loop_end - 1, LoopEventType, sizeof (nframes_t), (uint8_t *) &loop_start); - cout << "Pushing LoopEvent ts=" << loop_end-1 - << " start+this_read " << start+this_read << endl; - + _playback_buf->write(loop_end - 1, LoopEventType, sizeof (framepos_t), (uint8_t *) &loop_start); start = loop_start; } else { start += this_read; @@ -788,29 +818,28 @@ MidiDiskstream::do_refill () } /* at end: nothing to do */ - if (file_frame == max_frames) { + if (file_frame == max_framepos) { return 0; } // At this point we... assert(_playback_buf->write_space() > 0); // ... have something to write to, and - assert(file_frame <= max_frames); // ... something to write + assert(file_frame <= max_framepos); // ... something to write // now calculate how much time is in the ringbuffer. // and lets write as much as we need to get this to be midi_readahead; uint32_t frames_read = g_atomic_int_get(&_frames_read_from_ringbuffer); uint32_t frames_written = g_atomic_int_get(&_frames_written_to_ringbuffer); if ((frames_written - frames_read) >= midi_readahead) { - //cout << "MDS Nothing to do. all fine" << endl; return 0; } - nframes_t to_read = midi_readahead - (frames_written - frames_read); + framecnt_t to_read = midi_readahead - (frames_written - frames_read); //cout << "MDS read for midi_readahead " << to_read << " rb_contains: " // << frames_written - frames_read << endl; - to_read = min(to_read, (max_frames - file_frame)); + to_read = (framecnt_t) min ((framecnt_t) to_read, (framecnt_t) (max_framepos - file_frame)); if (read (file_frame, to_read, reversed)) { ret = -1; @@ -832,21 +861,23 @@ MidiDiskstream::do_refill () int MidiDiskstream::do_flush (RunContext /*context*/, bool force_flush) { - uint32_t to_write; + framecnt_t to_write; + framecnt_t total; int32_t ret = 0; - nframes_t total; - _write_data_count = 0; + if (!_write_source) { + return 0; + } - total = _session.transport_frame() - _last_flush_frame; + assert (!destructive()); - if (_last_flush_frame > _session.transport_frame() - || _last_flush_frame < capture_start_frame) { - _last_flush_frame = _session.transport_frame(); - } + _write_data_count = 0; + + total = _session.transport_frame() - _write_source->last_write_end(); - if (total == 0 || _capture_buf->read_space() == 0 - || (!force_flush && (total < disk_io_chunk_frames && was_recording))) { + if (total == 0 || + _capture_buf->read_space() == 0 || + (!force_flush && (total < disk_io_chunk_frames) && was_recording)) { goto out; } @@ -865,19 +896,18 @@ MidiDiskstream::do_flush (RunContext /*context*/, bool force_flush) ret = 1; } - to_write = disk_io_chunk_frames; - - assert(!destructive()); + if (force_flush) { + /* push out everything we have, right now */ + to_write = max_framecnt; + } else { + to_write = disk_io_chunk_frames; + } - if (record_enabled() && - ((_session.transport_frame() - _last_flush_frame > disk_io_chunk_frames) || - force_flush)) { - if ((!_write_source) || _write_source->midi_write (*_capture_buf, capture_start_frame, to_write) != to_write) { + if (record_enabled() && ((total > disk_io_chunk_frames) || force_flush)) { + if (_write_source->midi_write (*_capture_buf, get_capture_start_frame (0), to_write) != to_write) { error << string_compose(_("MidiDiskstream %1: cannot write to disk"), _id) << endmsg; return -1; - } else { - _last_flush_frame = _session.transport_frame(); - } + } } out: @@ -893,9 +923,8 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen MidiRegion::SourceList srcs; MidiRegion::SourceList::iterator src; vector::iterator ci; - bool mark_write_completed = false; - finish_capture (true); + finish_capture (); /* butler is already stopped, but there may be work to do to flush remaining data to disk. @@ -903,14 +932,14 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen while (more_work && !err) { switch (do_flush (TransportContext, true)) { - case 0: - more_work = false; - break; - case 1: - break; - case -1: - error << string_compose(_("MidiDiskstream \"%1\": cannot flush captured data to disk!"), _name) << endmsg; - err++; + case 0: + more_work = false; + break; + case 1: + break; + case -1: + error << string_compose(_("MidiDiskstream \"%1\": cannot flush captured data to disk!"), _name) << endmsg; + err++; } } @@ -924,8 +953,8 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen if (abort_capture) { if (_write_source) { - _write_source->mark_for_remove (); + _write_source->drop_references (); _write_source.reset(); } @@ -935,118 +964,137 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen assert(_write_source); - nframes_t total_capture = 0; + framecnt_t total_capture = 0; for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) { total_capture += (*ci)->frames; } - 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 (); - - /* make it not a stub anymore */ - - _write_source->unstubify (); - - /* 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. luckily, we can rely on - MidiSource::mark_streaming_write_completed() to have - already done the necessary work for that. - */ - - 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 rx (RegionFactory::create (srcs, plist)); - - region = boost::dynamic_pointer_cast (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_changes (); - _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); - - boost::shared_ptr rx (RegionFactory::create (srcs, plist)); - region = boost::dynamic_pointer_cast (rx); - } - - catch (failed_constructor& err) { - error << _("MidiDiskstream: could not create region for captured midi!") << endmsg; - continue; /* XXX is this OK? */ - } - - // cerr << "add new region, buffer position = " << buffer_position << " @ " << (*ci)->start << endl; - - 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)); - } - - mark_write_completed = true; + 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); + + /* set length in beats to entire capture length */ + + BeatsFramesConverter converter (_session.tempo_map(), capture_info.front()->start); + const double total_capture_beats = converter.from (total_capture); + _write_source->set_length_beats (total_capture_beats); + + /* flush to disk: this step differs from the audio path, + where all the data is already on disk. + */ + + _write_source->mark_midi_streaming_write_completed (Evoral::Sequence::ResolveStuckNotes, total_capture_beats); + + /* 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. luckily, we can rely on + MidiSource::mark_streaming_write_completed() to have + already done the necessary work for that. + */ + + 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 rx (RegionFactory::create (srcs, plist)); + + region = boost::dynamic_pointer_cast (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_changes (); + _playlist->freeze (); + + /* Session frame time of the initial capture in this pass, which is where the source starts */ + framepos_t initial_capture = 0; + if (!capture_info.empty()) { + initial_capture = capture_info.front()->start; + } + + for (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; + + /* start of this region is the offset between the start of its capture and the start of the whole pass */ + plist.add (Properties::start, (*ci)->start - initial_capture); + plist.add (Properties::length, (*ci)->frames); + plist.add (Properties::length_beats, converter.from((*ci)->frames)); + plist.add (Properties::name, region_name); + + boost::shared_ptr rx (RegionFactory::create (srcs, plist)); + region = boost::dynamic_pointer_cast (rx); + } + + catch (failed_constructor& err) { + error << _("MidiDiskstream: could not create region for captured midi!") << endmsg; + continue; /* XXX is this OK? */ + } + + // cerr << "add new region, buffer position = " << buffer_position << " @ " << (*ci)->start << endl; + + i_am_the_modifier++; + _playlist->add_region (region, (*ci)->start); + i_am_the_modifier--; + } + + _playlist->thaw (); + _session.add_command (new StatefulDiffCommand(_playlist)); + + } else { + + /* No data was recorded, so this capture will + effectively be aborted; do the same as we + do for an explicit abort. + */ + + if (_write_source) { + _write_source->mark_for_remove (); + _write_source->drop_references (); + _write_source.reset(); + } + } + } - use_new_write_source (0); + use_new_write_source (0); for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) { delete *ci; @@ -1061,7 +1109,7 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen } void -MidiDiskstream::transport_looped (nframes_t transport_frame) +MidiDiskstream::transport_looped (framepos_t transport_frame) { if (was_recording) { @@ -1077,20 +1125,20 @@ MidiDiskstream::transport_looped (nframes_t transport_frame) } } - finish_capture (true); + finish_capture (); // the next region will start recording via the normal mechanism // we'll set the start position to the current transport pos // no latency adjustment or capture offset needs to be made, as that already happened the first time capture_start_frame = transport_frame; first_recordable_frame = transport_frame; // mild lie - last_recordable_frame = max_frames; + last_recordable_frame = max_framepos; was_recording = true; } } void -MidiDiskstream::finish_capture (bool /*rec_monitors_input*/) +MidiDiskstream::finish_capture () { was_recording = false; @@ -1146,7 +1194,7 @@ MidiDiskstream::set_record_enabled (bool yn) void MidiDiskstream::engage_record_enable () { - bool rolling = _session.transport_speed() != 0.0f; + bool const rolling = _session.transport_speed() != 0.0f; g_atomic_int_set (&_record_enabled, 1); @@ -1154,8 +1202,6 @@ MidiDiskstream::engage_record_enable () _source_port->request_monitor_input (!(_session.config.get_auto_input() && rolling)); } - _write_source->mark_streaming_midi_write_started (_note_mode, _session.transport_frame()); - RecordEnableChanged (); /* EMIT SIGNAL */ } @@ -1163,38 +1209,19 @@ void MidiDiskstream::disengage_record_enable () { g_atomic_int_set (&_record_enabled, 0); - if (_source_port && Config->get_monitoring_model() == HardwareMonitoring) { - if (_source_port) { - _source_port->request_monitor_input (false); - } - } - RecordEnableChanged (); /* EMIT SIGNAL */ } XMLNode& MidiDiskstream::get_state () { - XMLNode* node = new XMLNode ("Diskstream"); + XMLNode& node (Diskstream::get_state()); char buf[64]; LocaleGuard lg (X_("POSIX")); - snprintf (buf, sizeof(buf), "0x%x", _flags); - node->add_property ("flags", buf); - - node->add_property("channel-mode", enum_2_string(get_channel_mode())); - + node.add_property("channel-mode", enum_2_string(get_channel_mode())); snprintf (buf, sizeof(buf), "0x%x", get_channel_mask()); - node->add_property("channel-mask", buf); - - node->add_property ("playlist", _playlist->name()); - - snprintf (buf, sizeof(buf), "%f", _visible_speed); - node->add_property ("speed", buf); - - node->add_property("name", _name); - id().print(buf, sizeof(buf)); - node->add_property("id", buf); + node.add_property("channel-mask", buf); if (_write_source && _session.get_record_enabled()) { @@ -1216,18 +1243,14 @@ MidiDiskstream::get_state () } cs_child->add_property (X_("at"), buf); - node->add_child_nocopy (*cs_child); + node.add_child_nocopy (*cs_child); } - if (_extra_xml) { - node->add_child_copy (*_extra_xml); - } - - return* node; + return node; } int -MidiDiskstream::set_state (const XMLNode& node, int /*version*/) +MidiDiskstream::set_state (const XMLNode& node, int version) { const XMLProperty* prop; XMLNodeList nlist = node.children(); @@ -1235,12 +1258,11 @@ MidiDiskstream::set_state (const XMLNode& node, int /*version*/) XMLNode* capture_pending_node = 0; LocaleGuard lg (X_("POSIX")); + /* prevent write sources from being created */ + in_set_state = true; for (niter = nlist.begin(); niter != nlist.end(); ++niter) { - /*if ((*niter)->name() == IO::state_node_name) { - deprecated_io_node = new XMLNode (**niter); - }*/ assert ((*niter)->name() != IO::state_node_name); if ((*niter)->name() == X_("CapturingSources")) { @@ -1248,20 +1270,8 @@ MidiDiskstream::set_state (const XMLNode& node, int /*version*/) } } - /* prevent write sources from being created */ - - in_set_state = true; - - if ((prop = node.property ("name")) != 0) { - _name = prop->value(); - } - - if ((prop = node.property ("id")) != 0) { - _id = prop->value (); - } - - if ((prop = node.property ("flags")) != 0) { - _flags = Flag (string_2_enum (prop->value(), _flags)); + if (Diskstream::set_state (node, version)) { + return -1; } ChannelMode channel_mode = AllChannels; @@ -1277,36 +1287,12 @@ MidiDiskstream::set_state (const XMLNode& node, int /*version*/) } } - set_channel_mode(channel_mode, channel_mask); - - if ((prop = node.property ("playlist")) == 0) { - return -1; - } - - { - bool had_playlist = (_playlist != 0); - - if (find_and_use_playlist (prop->value())) { - return -1; - } - - if (!had_playlist) { - _playlist->set_orig_diskstream_id (id()); - } - - if (capture_pending_node) { - use_pending_capture_data (*capture_pending_node); - } + if (capture_pending_node) { + use_pending_capture_data (*capture_pending_node); } - if ((prop = node.property ("speed")) != 0) { - double sp = atof (prop->value().c_str()); - - if (realtime_set_speed (sp, false)) { - non_realtime_set_speed (); - } - } + set_channel_mode (channel_mode, channel_mask); in_set_state = false; @@ -1322,16 +1308,11 @@ MidiDiskstream::use_new_write_source (uint32_t n) assert(n == 0); - _write_source.reset(); + _write_source.reset(); try { - /* file starts off as a stub file, it will be converted - when we're done with a capture pass, or when "stolen" - by the GUI. - */ - _write_source = boost::dynamic_pointer_cast( - _session.create_midi_source_for_session (0, name (), true)); + _session.create_midi_source_for_session (0, name ())); if (!_write_source) { throw failed_constructor(); @@ -1344,36 +1325,27 @@ MidiDiskstream::use_new_write_source (uint32_t n) return -1; } - _write_source->mark_streaming_midi_write_started (_note_mode, _session.transport_frame()); - return 0; } -list > +list > MidiDiskstream::steal_write_sources() { - list > ret; + list > ret; - /* put some data on the disk, even if its just a header for an empty file. - XXX should we not have a more direct method for doing this? Maybe not - since we don't want to mess around with the model/disk relationship - that the Source has to pay attention to. - */ - - boost::dynamic_pointer_cast(_write_source)->session_saved (); + /* put some data on the disk, even if its just a header for an empty file */ + boost::dynamic_pointer_cast (_write_source)->ensure_disk_file (); - /* make it visible/present */ - _write_source->unstubify (); - /* never let it go away */ - _write_source->mark_nonremovable (); + /* never let it go away */ + _write_source->mark_nonremovable (); - ret.push_back (_write_source); + ret.push_back (_write_source); - /* get a new one */ + /* get a new one */ - use_new_write_source (0); + use_new_write_source (0); - return ret; + return ret; } void @@ -1385,22 +1357,12 @@ MidiDiskstream::reset_write_sources (bool mark_write_complete, bool /*force*/) if (_write_source && mark_write_complete) { _write_source->mark_streaming_write_completed (); - } - use_new_write_source (0); -} - -int -MidiDiskstream::rename_write_sources () -{ - if (_write_source != 0) { - _write_source->set_source_name (_name.val(), destructive()); - /* XXX what to do if this fails ? */ } - return 0; + use_new_write_source (0); } void -MidiDiskstream::set_block_size (nframes_t /*nframes*/) +MidiDiskstream::set_block_size (pframes_t /*nframes*/) { } @@ -1419,23 +1381,15 @@ MidiDiskstream::monitor_input (bool yn) void MidiDiskstream::set_align_style_from_io () { - bool have_physical = false; - - if (_io == 0) { + if (_alignment_choice != Automatic) { return; } - get_input_sources (); - - if (_source_port && _source_port->flags() & JackPortIsPhysical) { - have_physical = true; - } + /* XXX Not sure what, if anything we can do with MIDI + as far as capture alignment etc. + */ - if (have_physical) { - set_align_style (ExistingMaterial); - } else { - set_align_style (CaptureTime); - } + set_align_style (ExistingMaterial); } @@ -1463,7 +1417,7 @@ MidiDiskstream::use_pending_capture_data (XMLNode& /*node*/) * so that an event at \a start has time = 0 */ void -MidiDiskstream::get_playback (MidiBuffer& dst, nframes_t start, nframes_t end) +MidiDiskstream::get_playback (MidiBuffer& dst, framepos_t start, framepos_t end) { dst.clear(); assert(dst.size() == 0); @@ -1473,13 +1427,23 @@ MidiDiskstream::get_playback (MidiBuffer& dst, nframes_t start, nframes_t end) return; } - // Translates stamps to be relative to start + // Translate stamps to be relative to start #ifndef NDEBUG + DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ( + "%1 MDS pre-read read %4..%5 from %2 write to %3\n", _name, + _playback_buf->get_read_ptr(), _playback_buf->get_write_ptr(), start, end)); +// cerr << "================\n"; +// _playback_buf->dump (cerr); +// cerr << "----------------\n"; + const size_t events_read = _playback_buf->read(dst, start, end); - 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())); + DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ( + "%1 MDS events read %2 range %3 .. %4 rspace %5 wspace %6 r@%7 w@%8\n", + _name, events_read, start, end, + _playback_buf->read_space(), _playback_buf->write_space(), + _playback_buf->get_read_ptr(), _playback_buf->get_write_ptr())); #else _playback_buf->read(dst, start, end); #endif @@ -1488,3 +1452,14 @@ MidiDiskstream::get_playback (MidiBuffer& dst, nframes_t start, nframes_t end) g_atomic_int_add(&_frames_read_from_ringbuffer, frames_read); } +bool +MidiDiskstream::set_name (string const & name) +{ + Diskstream::set_name (name); + + /* get a new write source so that its name reflects the new diskstream name */ + use_new_write_source (0); + + return true; +} +