MIDI bounce.
This commit is contained in:
parent
5f66300349
commit
0f759e9a93
|
@ -21,7 +21,10 @@
|
|||
#define __ardour_midi_buffer_h__
|
||||
|
||||
#include "evoral/midi_util.h"
|
||||
#include "evoral/EventSink.hpp"
|
||||
|
||||
#include "midi++/event.h"
|
||||
|
||||
#include "ardour/buffer.h"
|
||||
#include "ardour/parameter_types.h"
|
||||
|
||||
|
@ -29,7 +32,7 @@ namespace ARDOUR {
|
|||
|
||||
|
||||
/** Buffer containing 8-bit unsigned char (MIDI) data. */
|
||||
class LIBARDOUR_API MidiBuffer : public Buffer
|
||||
class LIBARDOUR_API MidiBuffer : public Buffer, public Evoral::EventSink<framepos_t>
|
||||
{
|
||||
public:
|
||||
typedef framepos_t TimeType;
|
||||
|
@ -55,6 +58,9 @@ public:
|
|||
bool insert_event(const Evoral::MIDIEvent<TimeType>& event);
|
||||
bool merge_in_place(const MidiBuffer &other);
|
||||
|
||||
/** EventSink interface for non-RT use (export, bounce). */
|
||||
uint32_t write(TimeType time, Evoral::EventType type, uint32_t size, const uint8_t* buf);
|
||||
|
||||
template<typename BufferType, typename EventType>
|
||||
class iterator_base
|
||||
{
|
||||
|
|
|
@ -632,7 +632,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
|
|||
|
||||
/* flattening stuff */
|
||||
|
||||
boost::shared_ptr<Region> write_one_track (AudioTrack&, framepos_t start, framepos_t end,
|
||||
boost::shared_ptr<Region> write_one_track (Track&, framepos_t start, framepos_t end,
|
||||
bool overwrite, std::vector<boost::shared_ptr<Source> >&, InterThreadInfo& wot,
|
||||
boost::shared_ptr<Processor> endpoint,
|
||||
bool include_endpoint, bool for_export, bool for_freeze);
|
||||
|
|
|
@ -250,6 +250,13 @@ MidiBuffer::insert_event(const Evoral::MIDIEvent<TimeType>& ev)
|
|||
return true;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
MidiBuffer::write(TimeType time, Evoral::EventType type, uint32_t size, const uint8_t* buf)
|
||||
{
|
||||
insert_event(Evoral::MIDIEvent<TimeType>(type, time, size, const_cast<uint8_t*>(buf)));
|
||||
return size;
|
||||
}
|
||||
|
||||
/** Reserve space for a new event in the buffer.
|
||||
*
|
||||
* This call is for copying MIDI directly into the buffer, the data location
|
||||
|
|
|
@ -560,26 +560,52 @@ MidiTrack::write_out_of_band_data (BufferSet& bufs, framepos_t /*start*/, framep
|
|||
}
|
||||
|
||||
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*/)
|
||||
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)
|
||||
{
|
||||
return -1;
|
||||
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
|
||||
|
|
|
@ -4386,7 +4386,7 @@ Session::freeze_all (InterThreadInfo& itt)
|
|||
}
|
||||
|
||||
boost::shared_ptr<Region>
|
||||
Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
|
||||
Session::write_one_track (Track& track, framepos_t start, framepos_t end,
|
||||
bool /*overwrite*/, vector<boost::shared_ptr<Source> >& srcs,
|
||||
InterThreadInfo& itt,
|
||||
boost::shared_ptr<Processor> endpoint, bool include_endpoint,
|
||||
|
@ -4394,7 +4394,7 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
|
|||
{
|
||||
boost::shared_ptr<Region> result;
|
||||
boost::shared_ptr<Playlist> playlist;
|
||||
boost::shared_ptr<AudioFileSource> fsource;
|
||||
boost::shared_ptr<Source> source;
|
||||
ChanCount diskstream_channels (track.n_channels());
|
||||
framepos_t position;
|
||||
framecnt_t this_chunk;
|
||||
|
@ -4416,8 +4416,8 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
|
|||
diskstream_channels = track.bounce_get_output_streams (diskstream_channels, endpoint,
|
||||
include_endpoint, for_export, for_freeze);
|
||||
|
||||
if (diskstream_channels.n_audio() < 1) {
|
||||
error << _("Cannot write a range with no audio.") << endmsg;
|
||||
if (diskstream_channels.n(track.data_type()) < 1) {
|
||||
error << _("Cannot write a range with no data.") << endmsg;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -4443,26 +4443,27 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
|
|||
|
||||
legal_playlist_name = legalize_for_path (playlist->name());
|
||||
|
||||
for (uint32_t chan_n = 0; chan_n < diskstream_channels.n_audio(); ++chan_n) {
|
||||
for (uint32_t chan_n = 0; chan_n < diskstream_channels.n(track.data_type()); ++chan_n) {
|
||||
|
||||
string base_name = string_compose ("%1-%2-bounce", playlist->name(), chan_n);
|
||||
string path = new_audio_source_path (legal_playlist_name, diskstream_channels.n_audio(), chan_n, false, true);
|
||||
string path = ((track.data_type() == DataType::AUDIO)
|
||||
? new_audio_source_path (legal_playlist_name, diskstream_channels.n_audio(), chan_n, false, true)
|
||||
: new_midi_source_path (legal_playlist_name));
|
||||
|
||||
if (path.empty()) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
try {
|
||||
fsource = boost::dynamic_pointer_cast<AudioFileSource> (
|
||||
SourceFactory::createWritable (DataType::AUDIO, *this, path, false, frame_rate()));
|
||||
source = SourceFactory::createWritable (track.data_type(), *this, path, false, frame_rate());
|
||||
}
|
||||
|
||||
catch (failed_constructor& err) {
|
||||
error << string_compose (_("cannot create new audio file \"%1\" for %2"), path, track.name()) << endmsg;
|
||||
error << string_compose (_("cannot create new file \"%1\" for %2"), path, track.name()) << endmsg;
|
||||
goto out;
|
||||
}
|
||||
|
||||
srcs.push_back (fsource);
|
||||
srcs.push_back (source);
|
||||
}
|
||||
|
||||
/* tell redirects that care that we are about to use a much larger
|
||||
|
@ -4512,11 +4513,20 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
|
|||
uint32_t n = 0;
|
||||
for (vector<boost::shared_ptr<Source> >::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) {
|
||||
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
|
||||
boost::shared_ptr<MidiSource> ms;
|
||||
|
||||
if (afs) {
|
||||
if (afs->write (buffers.get_audio(n).data(latency_skip), current_chunk) != current_chunk) {
|
||||
goto out;
|
||||
}
|
||||
} else if ((ms = boost::dynamic_pointer_cast<MidiSource>(*src))) {
|
||||
Source::Lock lock(ms->mutex());
|
||||
ms->mark_streaming_write_started(lock);
|
||||
|
||||
const MidiBuffer& buf = buffers.get_midi(0);
|
||||
for (MidiBuffer::const_iterator i = buf.begin(); i != buf.end(); ++i) {
|
||||
ms->append_event_frames(lock, *i, ms->timeline_position());
|
||||
}
|
||||
}
|
||||
}
|
||||
latency_skip = 0;
|
||||
|
@ -4553,10 +4563,14 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
|
|||
|
||||
for (vector<boost::shared_ptr<Source> >::iterator src=srcs.begin(); src != srcs.end(); ++src) {
|
||||
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
|
||||
boost::shared_ptr<MidiSource> ms;
|
||||
|
||||
if (afs) {
|
||||
afs->update_header (position, *xnow, now);
|
||||
afs->flush_header ();
|
||||
} else if ((ms = boost::dynamic_pointer_cast<MidiSource>(*src))) {
|
||||
Source::Lock lock(ms->mutex());
|
||||
ms->mark_streaming_write_completed(lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4575,12 +4589,7 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
|
|||
out:
|
||||
if (!result) {
|
||||
for (vector<boost::shared_ptr<Source> >::iterator src = srcs.begin(); src != srcs.end(); ++src) {
|
||||
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
|
||||
|
||||
if (afs) {
|
||||
afs->mark_for_remove ();
|
||||
}
|
||||
|
||||
(*src)->mark_for_remove ();
|
||||
(*src)->drop_references ();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue