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:
David Robillard 2008-05-03 21:55:43 +00:00
parent d2465f311f
commit e55e3fde7c
10 changed files with 76 additions and 121 deletions

View file

@ -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

View file

@ -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; }

View file

@ -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();

View file

@ -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 */

View file

@ -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;
}

View file

@ -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"));

View file

@ -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;
}

View file

@ -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 {

View file

@ -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;
}

View file

@ -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());
}