mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-06 14:54:56 +01:00
Comment out excessive terminal output.
Write all events (not just notes) to SMF file from MidiModel (just use iterator instead of hand-hacked MidiModel::write_to). Various MIDI bug fixes. git-svn-id: svn://localhost/ardour2/branches/3.0@3312 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
d2465f311f
commit
e55e3fde7c
10 changed files with 76 additions and 121 deletions
|
|
@ -623,7 +623,7 @@ AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkEvent
|
|||
bool
|
||||
AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
|
||||
{
|
||||
return cut_copy_clear_one (*_line, selection, op);
|
||||
return (_line ? cut_copy_clear_one (*_line, selection, op) : false);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ public:
|
|||
*/
|
||||
class MidiModel : public boost::noncopyable, public Automatable {
|
||||
public:
|
||||
MidiModel(MidiSource *s, size_t size=0);
|
||||
MidiModel(MidiSource* s, size_t size=0);
|
||||
|
||||
void write_lock();
|
||||
void write_unlock();
|
||||
|
|
@ -91,7 +91,6 @@ public:
|
|||
inline size_t n_notes() const { return _notes.size(); }
|
||||
inline bool empty() const { return _notes.size() == 0 && _controls.size() == 0; }
|
||||
|
||||
|
||||
inline static bool note_time_comparator (const boost::shared_ptr<const Note> a,
|
||||
const boost::shared_ptr<const Note> b) {
|
||||
return a->time() < b->time();
|
||||
|
|
@ -149,7 +148,8 @@ public:
|
|||
void set_edited(bool yn) { _edited = yn; }
|
||||
bool write_to(boost::shared_ptr<MidiSource> source);
|
||||
|
||||
// MidiModel doesn't use the normal AutomationList serialisation code, as CC data is in the .mid
|
||||
// MidiModel doesn't use the normal AutomationList serialisation code
|
||||
// since controller data is stored in the .mid
|
||||
XMLNode& get_state();
|
||||
int set_state(const XMLNode&) { return 0; }
|
||||
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ class SMFSource : public MidiSource {
|
|||
bool writable() const { return _flags & Writable; }
|
||||
|
||||
int open();
|
||||
void close();
|
||||
void seek_to_end();
|
||||
void write_footer();
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,6 @@ class SndFileSource : public AudioFileSource {
|
|||
|
||||
void init ();
|
||||
int open();
|
||||
void close();
|
||||
int setup_broadcast_info (nframes_t when, struct tm&, time_t);
|
||||
|
||||
/* destructive */
|
||||
|
|
|
|||
|
|
@ -556,7 +556,7 @@ AudioEngine::register_port (DataType dtype, const string& portname, bool input,
|
|||
{
|
||||
Port* newport = 0;
|
||||
|
||||
cerr << "trying to register port with name " << portname << endl;
|
||||
/*cerr << "trying to register port with name " << portname << endl;*/
|
||||
try {
|
||||
if (dtype == DataType::AUDIO) {
|
||||
newport = new AudioPort (portname, (input ? Port::IsInput : Port::IsOutput), publish, frames_per_cycle());
|
||||
|
|
@ -566,16 +566,16 @@ AudioEngine::register_port (DataType dtype, const string& portname, bool input,
|
|||
throw unknown_type();
|
||||
}
|
||||
|
||||
cerr << "successfully got port " << portname << " with address " << newport << endl;
|
||||
/*cerr << "successfully got port " << portname << " with address " << newport << endl;*/
|
||||
|
||||
RCUWriter<Ports> writer (ports);
|
||||
boost::shared_ptr<Ports> ps = writer.get_copy ();
|
||||
cerr << "Address of ports list: " << ps << endl
|
||||
<< "Ports set size before insert: " << ps->size() << endl;
|
||||
/*cerr << "Address of ports list: " << ps << endl
|
||||
<< "Ports set size before insert: " << ps->size() << endl;*/
|
||||
ps->insert (ps->begin(), newport);
|
||||
cerr << "Ports set size after insert: " << ps->size() << endl;
|
||||
/* writer goes out of scope, forces update */
|
||||
/*cerr << "Ports set size after insert: " << ps->size() << endl;*/
|
||||
|
||||
/* writer goes out of scope, forces update */
|
||||
|
||||
return newport;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1436,10 +1436,6 @@ AutomationList::get_state ()
|
|||
XMLNode&
|
||||
AutomationList::state (bool full)
|
||||
{
|
||||
cerr << "getting ";
|
||||
if(full)
|
||||
cerr << "full ";
|
||||
cerr << "state for AutomationList " << _parameter.to_string() << " list size: " << size() << endl;
|
||||
XMLNode* root = new XMLNode (X_("AutomationList"));
|
||||
char buf[64];
|
||||
LocaleGuard lg (X_("POSIX"));
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
|
|||
_locked = false;
|
||||
}
|
||||
} else {
|
||||
printf("MIDI Iterator = %X @ %lf\n", _event.type(), _event.time());
|
||||
//printf("New MIDI Iterator = %X @ %lf\n", _event.type(), _event.time());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -161,7 +161,7 @@ const MidiModel::const_iterator& MidiModel::const_iterator::operator++()
|
|||
assert((_event.is_note() || _event.is_cc() || _event.is_pgm_change() || _event.is_pitch_bender() || _event.is_channel_aftertouch()));
|
||||
|
||||
// Increment past current control event
|
||||
if (_control_iter != _control_iters.end() && _control_iter->automation_list && _event.is_cc()) {
|
||||
if (!_event.is_note() && _control_iter != _control_iters.end() && _control_iter->automation_list) {
|
||||
double x, y;
|
||||
cerr << "control_iter x:" << _control_iter->x << " y:" << _control_iter->y << endl;
|
||||
const bool ret = _control_iter->automation_list->rt_safe_earliest_event_unlocked(
|
||||
|
|
@ -212,24 +212,24 @@ const MidiModel::const_iterator& MidiModel::const_iterator::operator++()
|
|||
// Use the next earliest controller iff it's earlier than the note event
|
||||
if (_control_iter != _control_iters.end()
|
||||
&& _control_iter->x != DBL_MAX
|
||||
&& _control_iter != old_control_iter)
|
||||
)//&& _control_iter != old_control_iter)
|
||||
if (type == NIL || _control_iter->x < t)
|
||||
type = AUTOMATION;
|
||||
|
||||
if (type == NOTE_ON) {
|
||||
cerr << "********** MIDI Iterator = note on" << endl;
|
||||
//cerr << "********** MIDI Iterator = note on" << endl;
|
||||
_event = MIDI::Event((*_note_iter)->on_event(), false);
|
||||
_active_notes.push(*_note_iter);
|
||||
++_note_iter;
|
||||
} else if (type == NOTE_OFF) {
|
||||
cerr << "********** MIDI Iterator = note off" << endl;
|
||||
//cerr << "********** MIDI Iterator = note off" << endl;
|
||||
_event = MIDI::Event(_active_notes.top()->off_event(), false);
|
||||
_active_notes.pop();
|
||||
} else if (type == AUTOMATION) {
|
||||
cerr << "********** MIDI Iterator = AUTOMATION" << endl;
|
||||
//cerr << "********** MIDI Iterator = Automation" << endl;
|
||||
_model->control_to_midi_event(_event, *_control_iter);
|
||||
} else {
|
||||
cerr << "********** MIDI Iterator = END" << endl;
|
||||
//cerr << "********** MIDI Iterator = End" << endl;
|
||||
_is_end = true;
|
||||
}
|
||||
|
||||
|
|
@ -483,7 +483,8 @@ void MidiModel::append(const MIDI::Event& ev)
|
|||
write_lock();
|
||||
_edited = true;
|
||||
|
||||
cerr << "MidiModel::append event type: " << hex << "0x" << int(ev.type()) << endl;
|
||||
/*cerr << "MidiModel append event type: "
|
||||
<< hex << "0x" << (int)ev.type() << endl;*/
|
||||
|
||||
assert(_notes.empty() || ev.time() >= _notes.back()->time());
|
||||
assert(_writing);
|
||||
|
|
@ -507,7 +508,7 @@ void MidiModel::append(const MIDI::Event& ev)
|
|||
append_automation_event_unlocked(MidiChannelAftertouchAutomation,
|
||||
ev.channel(), ev.time(), ev.channel_aftertouch(), 0);
|
||||
} else {
|
||||
printf("MM Unknown event type %X\n", ev.type());
|
||||
printf("WARNING: MidiModel: Unknown event type %X\n", ev.type());
|
||||
}
|
||||
|
||||
write_unlock();
|
||||
|
|
@ -607,7 +608,7 @@ void MidiModel::append_automation_event_unlocked(AutomationType type,
|
|||
Parameter param(type, id, chan);
|
||||
boost::shared_ptr<AutomationControl> control = Automatable::control(param, true);
|
||||
control->list()->fast_simple_add(time, value);
|
||||
cerr << "control list size after fast simple add: " << control->list()->size() << endl;
|
||||
/*cerr << "control list size after fast simple add: " << control->list()->size() << endl;*/
|
||||
}
|
||||
|
||||
void MidiModel::add_note_unlocked(const boost::shared_ptr<Note> note)
|
||||
|
|
@ -877,76 +878,27 @@ struct EventTimeComparator {
|
|||
}
|
||||
};
|
||||
|
||||
/** Write the model to a MidiSource (i.e. save the model).
|
||||
* This is different from manually using read to write to a source in that
|
||||
* note off events are written regardless of the track mode. This is so the
|
||||
* user can switch a recorded track (with note durations from some instrument)
|
||||
* to percussive, save, reload, then switch it back to sustained without
|
||||
* destroying the original note durations.
|
||||
*/
|
||||
bool MidiModel::write_to(boost::shared_ptr<MidiSource> source)
|
||||
{
|
||||
cerr << "Writing model to " << source->name() << endl;
|
||||
|
||||
/* This could be done using a temporary MidiRingBuffer and using
|
||||
* MidiModel::read and MidiSource::write, but this is more efficient
|
||||
* and doesn't require any buffer size assumptions (ie it's worth
|
||||
* the code duplication).
|
||||
*
|
||||
* This is also different from read in that note off events are written
|
||||
* regardless of the track mode. This is so the user can switch a
|
||||
* recorded track (with note durations from some instrument) to percussive,
|
||||
* save, reload, then switch it back to sustained preserving the original
|
||||
* note durations.
|
||||
*/
|
||||
|
||||
read_lock();
|
||||
|
||||
LaterNoteEndComparator cmp;
|
||||
ActiveNotes active_notes(cmp);
|
||||
|
||||
EventTimeComparator comp;
|
||||
typedef std::priority_queue<
|
||||
const MIDI::Event*,
|
||||
std::deque<const MIDI::Event*>,
|
||||
EventTimeComparator> MidiEvents;
|
||||
|
||||
MidiEvents events(comp);
|
||||
|
||||
/* Why sort manually, when a priority queue does the job for us,
|
||||
* (I am probably wrong here, but I needed that to test program
|
||||
* change code quickly) ???
|
||||
* */
|
||||
// Foreach note
|
||||
for (Notes::const_iterator n = _notes.begin(); n != _notes.end(); ++n) {
|
||||
|
||||
// Write any pending note offs earlier than this note on
|
||||
while ( !active_notes.empty() ) {
|
||||
const boost::shared_ptr<const Note> earliest_off =
|
||||
active_notes.top();
|
||||
const MIDI::Event& off_ev = earliest_off->off_event();
|
||||
if (off_ev.time() <= (*n)->time()) {
|
||||
events.push(&off_ev);
|
||||
active_notes.pop();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Write this note on
|
||||
events.push(&(*n)->on_event());
|
||||
if ((*n)->duration() > 0)
|
||||
active_notes.push(*n);
|
||||
}
|
||||
|
||||
// Write any trailing note offs
|
||||
while ( !active_notes.empty() ) {
|
||||
events.push(&active_notes.top()->off_event());
|
||||
active_notes.pop();
|
||||
}
|
||||
|
||||
while (!events.empty()) {
|
||||
source->append_event_unlocked(Frames, *events.top());
|
||||
//cerr << "MidiModel::write_to appending event with time:" << dec << int(events.top()->time()) << hex << " buffer: 0x" << int(events.top()->buffer()[0]) << " 0x" << int(events.top()->buffer()[1]) << " 0x" << int(events.top()->buffer()[2]) << endl;
|
||||
events.pop();
|
||||
}
|
||||
|
||||
_edited = false;
|
||||
const NoteMode old_note_mode = _note_mode;
|
||||
_note_mode = Sustained;
|
||||
|
||||
for (const_iterator i = begin(); i != end(); ++i)
|
||||
source->append_event_unlocked(Frames, *i);
|
||||
|
||||
_note_mode = old_note_mode;
|
||||
|
||||
read_unlock();
|
||||
_edited = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,8 +131,8 @@ MidiRegion::master_read_at (MidiRingBuffer& out, nframes_t position, nframes_t d
|
|||
nframes_t
|
||||
MidiRegion::_read_at (const SourceList& srcs, MidiRingBuffer& dst, nframes_t position, nframes_t dur, uint32_t chan_n, NoteMode mode) const
|
||||
{
|
||||
cerr << "reading from region " << _name << " position: " << _position << " start: " << _start << endl;
|
||||
cerr << _name << "._read_at(" << position << ") - " << position << " duration: " << dur << endl;
|
||||
/*cerr << "MidiRegion " << _name << "._read_at(" << position << ") - "
|
||||
<< position << " duration: " << dur << endl;*/
|
||||
|
||||
nframes_t internal_offset = 0;
|
||||
nframes_t src_offset = 0;
|
||||
|
|
@ -174,7 +174,7 @@ MidiRegion::_read_at (const SourceList& srcs, MidiRingBuffer& dst, nframes_t pos
|
|||
|
||||
nframes_t output_buffer_position = 0;
|
||||
nframes_t negative_output_buffer_position = 0;
|
||||
if(_position >= _start) {
|
||||
if (_position >= _start) {
|
||||
// handle resizing of beginnings of regions correctly
|
||||
output_buffer_position = _position - _start;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -56,8 +56,6 @@ Parameter::Parameter(const std::string& str)
|
|||
sscanf(str.c_str(), "midicc-%d-%d", &channel, &_id);
|
||||
assert(channel < 16);
|
||||
_channel = channel;
|
||||
cout << "LOADED PARAMETER " << str << " chan " << _channel << " id " << _id << endl;
|
||||
//_id = atoi(str.c_str()+7);
|
||||
} else {
|
||||
PBD::warning << "Unknown Parameter '" << str << "'" << endmsg;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,6 +133,14 @@ SMFSource::init (string pathstr, bool must_exist)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/** Attempt to open the SMF file for reading and writing.
|
||||
*
|
||||
* Currently SMFSource is always read/write.
|
||||
*
|
||||
* \return 0 on success
|
||||
* -1 if the file can not be opened for reading,
|
||||
* -2 if the file can not be opened for writing
|
||||
*/
|
||||
int
|
||||
SMFSource::open()
|
||||
{
|
||||
|
|
@ -153,6 +161,11 @@ SMFSource::open()
|
|||
// We're making a new file
|
||||
} else {
|
||||
_fd = fopen(path().c_str(), "w+");
|
||||
if (_fd == NULL) {
|
||||
cerr << "ERROR: Can not open SMF file " << path() << " for writing: " <<
|
||||
strerror(errno) << endl;
|
||||
return -2;
|
||||
}
|
||||
_track_size = 4;
|
||||
|
||||
// Write a tentative header just to pad things out so writing happens in the right spot
|
||||
|
|
@ -160,10 +173,21 @@ SMFSource::open()
|
|||
write_footer();
|
||||
seek_to_end();
|
||||
}
|
||||
|
||||
|
||||
return (_fd == 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
void
|
||||
SMFSource::close()
|
||||
{
|
||||
if (_fd) {
|
||||
flush_header();
|
||||
flush_footer();
|
||||
fclose(_fd);
|
||||
_fd = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SMFSource::seek_to_end()
|
||||
{
|
||||
|
|
@ -171,7 +195,7 @@ SMFSource::seek_to_end()
|
|||
}
|
||||
|
||||
int
|
||||
SMFSource::flush_header ()
|
||||
SMFSource::flush_header()
|
||||
{
|
||||
// FIXME: write timeline position somehow?
|
||||
|
||||
|
|
@ -211,8 +235,6 @@ SMFSource::flush_footer()
|
|||
void
|
||||
SMFSource::write_footer()
|
||||
{
|
||||
//cerr << "SMF " << name() << " writing EOT at byte " << ftell(_fd) << endl;
|
||||
|
||||
write_var_len(0);
|
||||
char eot[3] = { 0xFF, 0x2F, 0x00 }; // end-of-track meta-event
|
||||
fwrite(eot, 1, 3, _fd);
|
||||
|
|
@ -318,11 +340,11 @@ SMFSource::read_event(uint32_t* delta_t, uint32_t* size, Byte** buf) const
|
|||
if (event_size > 1)
|
||||
fread((*buf) + 1, 1, *size - 1, _fd);
|
||||
|
||||
printf("%s read event: delta = %u, size = %u, data = ", _name.c_str(), *delta_t, *size);
|
||||
/*printf("%s read event: delta = %u, size = %u, data = ", _name.c_str(), *delta_t, *size);
|
||||
for (size_t i=0; i < *size; ++i) {
|
||||
printf("%X ", (*buf)[i]);
|
||||
}
|
||||
printf("\n");
|
||||
printf("\n");*/
|
||||
|
||||
return (int)*size;
|
||||
}
|
||||
|
|
@ -451,12 +473,13 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt)
|
|||
void
|
||||
SMFSource::append_event_unlocked(EventTimeUnit unit, const MIDI::Event& ev)
|
||||
{
|
||||
//printf("%s - append chan = %u, time = %lf, size = %u, data = ", _path.c_str(), (unsigned)ev.channel(), ev.time(), ev.size());
|
||||
/*printf("%s - append chan = %u, time = %lf, size = %u, data = ",
|
||||
name().c_str(), (unsigned)ev.channel(), ev.time(), ev.size());
|
||||
for (size_t i=0; i < ev.size(); ++i) {
|
||||
printf("%X ", ev.buffer()[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("\n");*/
|
||||
|
||||
assert(ev.time() >= 0);
|
||||
assert(ev.time() >= _last_ev_time);
|
||||
|
||||
|
|
@ -535,6 +558,7 @@ SMFSource::mark_streaming_midi_write_started (NoteMode mode, nframes_t start_fra
|
|||
{
|
||||
MidiSource::mark_streaming_midi_write_started (mode, start_frame);
|
||||
_last_ev_time = 0;
|
||||
fseek(_fd, _header_size, 0);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -546,20 +570,9 @@ SMFSource::mark_streaming_write_completed ()
|
|||
return;
|
||||
}
|
||||
|
||||
_model->set_edited(false);
|
||||
flush_header();
|
||||
flush_footer();
|
||||
|
||||
#if 0
|
||||
Glib::Mutex::Lock lm (_lock);
|
||||
|
||||
|
||||
next_peak_clear_should_notify = true;
|
||||
|
||||
if (_peaks_built || pending_peak_builds.empty()) {
|
||||
_peaks_built = true;
|
||||
PeaksReady (); /* EMIT SIGNAL */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -861,13 +874,8 @@ SMFSource::load_model(bool lock, bool force_reload)
|
|||
if (lock)
|
||||
Glib::Mutex::Lock lm (_lock);
|
||||
|
||||
if (_model && !force_reload && !_model->empty()) {
|
||||
//cerr << _name << " NOT reloading model " << _model.get() << " (" << _model->n_notes()
|
||||
// << " notes)" << endl;
|
||||
if (_model && !force_reload && !_model->empty())
|
||||
return;
|
||||
} else {
|
||||
cerr << _name << " loading model" << endl;
|
||||
}
|
||||
|
||||
if (! _model) {
|
||||
_model = boost::shared_ptr<MidiModel>(new MidiModel(this));
|
||||
|
|
@ -912,6 +920,7 @@ SMFSource::load_model(bool lock, bool force_reload)
|
|||
}
|
||||
|
||||
_model->end_write(false);
|
||||
_model->set_edited(false);
|
||||
|
||||
free(ev.buffer());
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue