diff --git a/libs/ardour/ardour/smf_source.h b/libs/ardour/ardour/smf_source.h index 9e215bf5a2..8d818e4c6b 100644 --- a/libs/ardour/ardour/smf_source.h +++ b/libs/ardour/ardour/smf_source.h @@ -111,7 +111,17 @@ class SMFSource : public MidiSource { int open(); void close(); - void seek_to_end(); + + /** + * This method is only used by flush_footer() to find the right seek position + * for the footer (at the end after recording or -4 offset ro SEEK_END + * if a footer is already present) + */ + void seek_to_footer_position(); + + /** + * write the track footer at the current seek position + */ void write_footer(); void write_chunk_header(const char id[4], uint32_t length); diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc index 4d1c78af9d..a39074747b 100644 --- a/libs/ardour/smf_source.cc +++ b/libs/ardour/smf_source.cc @@ -170,7 +170,8 @@ SMFSource::open() // Write a tentative header just to pad things out so writing happens in the right spot flush_header(); - flush_footer(); + // this is the first footer written, so we dont need to seek for the footer + write_footer(); } return (_fd == 0) ? -1 : 0; @@ -188,9 +189,24 @@ SMFSource::close() } void -SMFSource::seek_to_end() +SMFSource::seek_to_footer_position() { + uint8_t buffer[4]; + + // lets check if there is a track end marker at the end of the data fseek(_fd, -4, SEEK_END); + size_t read_bytes = fread(buffer, sizeof(uint8_t), 4, _fd); + if( (read_bytes == 4) && + buffer[0] == 0x00 && + buffer[1] == 0xFF && + buffer[2] == 0x2F && + buffer[3] == 0x00) { + // there is one, so overwrite it + fseek(_fd, -4, SEEK_END); + } else { + // there is none, so append + fseek(_fd, 0, SEEK_END); + } } int @@ -198,7 +214,7 @@ SMFSource::flush_header() { // FIXME: write timeline position somehow? - //cerr << "SMF Flushing header\n"; + //cerr << path() << " SMF Flushing header\n"; assert(_fd); @@ -225,7 +241,8 @@ SMFSource::flush_header() int SMFSource::flush_footer() { - seek_to_end(); + //cerr << path() << " SMF Flushing footer\n"; + seek_to_footer_position(); write_footer(); return 0; @@ -332,18 +349,15 @@ SMFSource::read_event(uint32_t* delta_t, uint32_t* size, Byte** buf) const *size = event_size; - /*if (ev.buffer == NULL) - ev.buffer = (Byte*)malloc(sizeof(Byte) * ev.size);*/ - (*buf)[0] = (unsigned char)status; 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("SMFSource %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; } @@ -449,8 +463,13 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt) assert(time >= _timeline_position); time -= _timeline_position; - + const MIDI::Event ev(time, size, buf); + if (! (ev.is_channel_event() || ev.is_smf_meta_event() || ev.is_sysex()) ) { + //cerr << "SMFSource: WARNING: caller tried to write non SMF-Event of type " << std::hex << int(ev.buffer()[0]) << endl; + continue; + } + append_event_unlocked(Frames, ev); if (_model) @@ -472,12 +491,12 @@ 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 = ", - name().c_str(), (unsigned)ev.channel(), ev.time(), ev.size()); + /*printf("SMFSource: %s - append_event_unlocked 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); diff --git a/libs/midi++2/midi++/event.h b/libs/midi++2/midi++/event.h index 79f78c35e9..7f792af1e9 100644 --- a/libs/midi++2/midi++/event.h +++ b/libs/midi++2/midi++/event.h @@ -181,20 +181,24 @@ struct Event { inline uint8_t velocity() const { return (_buffer[2]); } inline uint8_t cc_number() const { return (_buffer[1]); } inline uint8_t cc_value() const { return (_buffer[2]); } - inline uint16_t pitch_bender_value() const { return (((0x7F & _buffer[1]) << 7) | (0x7F & _buffer[2])); } inline uint8_t pitch_bender_lsb() const { return (_buffer[1]); } inline uint8_t pitch_bender_msb() const { return (_buffer[2]); } + inline uint16_t pitch_bender_value() const { return (((0x7F & _buffer[2]) << 7) | (0x7F & _buffer[1])); } inline uint8_t pgm_number() const { return (_buffer[1]); } inline void set_pgm_number(uint8_t number){ _buffer[1] = number; } inline uint8_t aftertouch() const { return (_buffer[1]); } inline uint8_t channel_aftertouch() const { return (_buffer[1]); } + // midi channel events range from 0x80 to 0xE0 + inline bool is_channel_event() const { return (0x80 <= type()) && (type() <= 0xE0); } + inline bool is_smf_meta_event() const { return _buffer[0] == 0xFF; } + inline bool is_sysex() const { return _buffer[0] == 0xF0 || _buffer[0] == 0xF7; } inline const uint8_t* buffer() const { return _buffer; } inline uint8_t*& buffer() { return _buffer; } private: double _time; /**< Sample index (or beat time) at which event is valid */ uint32_t _size; /**< Number of uint8_ts of data in \a buffer */ - uint8_t* _buffer; /**< Raw MIDI data */ + uint8_t* _buffer; /**< Raw MIDI data */ #ifdef MIDI_EVENT_ALLOW_ALLOC bool _owns_buffer; /**< Whether buffer is locally allocated */