along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <cmath>
+
+#ifdef COMPILER_MSVC
+#include <float.h>
+
+// 'std::isinf()' and 'std::isnan()' are not available in MSVC.
+#define isinf_local(val) !((bool)_finite((double)val))
+#define isnan_local(val) (bool)_isnan((double)val)
+#else
+#define isinf_local std::isinf
+#define isnan_local std::isnan
+#endif
#include "pbd/ffs.h"
#include "pbd/enumwriter.h"
#include "ardour/buffer_set.h"
#include "ardour/debug.h"
#include "ardour/delivery.h"
+#include "ardour/event_type_map.h"
#include "ardour/meter.h"
#include "ardour/midi_diskstream.h"
#include "ardour/midi_playlist.h"
#include "ardour/midi_port.h"
#include "ardour/midi_track.h"
+#include "ardour/parameter_types.h"
#include "ardour/port.h"
#include "ardour/processor.h"
#include "ardour/session.h"
* the last argument ("stop on overflow in destination") so that we'll
* ship the rest out next time.
*
- * the (nframes-1) argument puts all these events at the last
+ * the Port::port_offset() + (nframes-1) argument puts all these events at the last
* possible position of the output buffer, so that we do not
- * violate monotonicity when writing.
+ * violate monotonicity when writing. Port::port_offset() will
+ * be non-zero if we're in a split process cycle.
*/
-
- _immediate_events.read (buf, 0, 1, nframes-1, true);
+ _immediate_events.read (buf, 0, 1, Port::port_offset() + nframes - 1, true);
}
}
int
-MidiTrack::export_stuff (BufferSet& /*bufs*/, framepos_t /*start_frame*/, framecnt_t /*nframes*/,
- boost::shared_ptr<Processor> /*endpoint*/, bool /*include_endpoint*/, bool /*for_export*/, bool /*for_freeze*/)
-{
- return -1;
+MidiTrack::export_stuff (BufferSet& buffers,
+ framepos_t start,
+ framecnt_t nframes,
+ boost::shared_ptr<Processor> endpoint,
+ bool include_endpoint,
+ bool for_export,
+ bool for_freeze)
+{
+ if (buffers.count().n_midi() == 0) {
+ return -1;
+ }
+
+ boost::shared_ptr<MidiDiskstream> diskstream = midi_diskstream();
+
+ Glib::Threads::RWLock::ReaderLock rlock (_processor_lock);
+
+ boost::shared_ptr<MidiPlaylist> mpl = boost::dynamic_pointer_cast<MidiPlaylist>(diskstream->playlist());
+ if (!mpl) {
+ return -2;
+ }
+
+ buffers.get_midi(0).clear();
+ if (mpl->read(buffers.get_midi(0), start, nframes, 0) != nframes) {
+ return -1;
+ }
+
+ //bounce_process (buffers, start, nframes, endpoint, include_endpoint, for_export, for_freeze);
+
+ return 0;
}
boost::shared_ptr<Region>
-MidiTrack::bounce (InterThreadInfo& /*itt*/)
+MidiTrack::bounce (InterThreadInfo& itt)
{
- std::cerr << "MIDI bounce currently unsupported" << std::endl;
- return boost::shared_ptr<Region> ();
+ return bounce_range (_session.current_start_frame(), _session.current_end_frame(), itt, main_outs(), false);
}
-
boost::shared_ptr<Region>
-MidiTrack::bounce_range (framepos_t /*start*/, framepos_t /*end*/, InterThreadInfo& /*itt*/,
- boost::shared_ptr<Processor> /*endpoint*/, bool /*include_endpoint*/)
+MidiTrack::bounce_range (framepos_t start,
+ framepos_t end,
+ InterThreadInfo& itt,
+ boost::shared_ptr<Processor> endpoint,
+ bool include_endpoint)
{
- std::cerr << "MIDI bounce range currently unsupported" << std::endl;
- return boost::shared_ptr<Region> ();
+ vector<boost::shared_ptr<Source> > srcs;
+ return _session.write_one_track (*this, start, end, false, srcs, itt, endpoint, include_endpoint, false, false);
}
void
cerr << "WARNING: Ignoring illegal immediate MIDI event" << endl;
return false;
}
- const uint32_t type = EventTypeMap::instance().midi_event_type(buf[0]);
- return (_immediate_events.write(0, type, size, buf) == size);
+ const uint32_t type = midi_parameter_type(buf[0]);
+ return (_immediate_events.write (0, type, size, buf) == size);
}
void
void
MidiTrack::MidiControl::set_value(double val)
{
+ const Evoral::Parameter ¶meter = _list ? _list->parameter() : Control::parameter();
+ const Evoral::ParameterDescriptor &desc = EventTypeMap::instance().descriptor(parameter);
+
bool valid = false;
- if (isinf(val)) {
+ if (isinf_local(val)) {
cerr << "MIDIControl value is infinity" << endl;
- } else if (isnan(val)) {
+ } else if (isnan_local(val)) {
cerr << "MIDIControl value is NaN" << endl;
- } else if (val < _list->parameter().min()) {
- cerr << "MIDIControl value is < " << _list->parameter().min() << endl;
- } else if (val > _list->parameter().max()) {
- cerr << "MIDIControl value is > " << _list->parameter().max() << endl;
+ } else if (val < desc.lower) {
+ cerr << "MIDIControl value is < " << desc.lower << endl;
+ } else if (val > desc.upper) {
+ cerr << "MIDIControl value is > " << desc.upper << endl;
} else {
valid = true;
}
return;
}
- assert(val <= _list->parameter().max());
- if ( ! automation_playback()) {
+ assert(val <= desc.upper);
+ if ( ! _list || ! automation_playback()) {
size_t size = 3;
- uint8_t ev[3] = { _list->parameter().channel(), uint8_t (val), 0 };
- switch(_list->parameter().type()) {
+ uint8_t ev[3] = { parameter.channel(), uint8_t (val), 0 };
+ switch(parameter.type()) {
case MidiCCAutomation:
ev[0] += MIDI_CMD_CONTROL;
- ev[1] = _list->parameter().id();
+ ev[1] = parameter.id();
ev[2] = int(val);
break;