Use double MIDI timestamps (towards tempo based time, and more-than-sample-accurate LV2 MIDI plugin application).
Eliminate double iteration over MIDIRingBuffer read to translate timestamps. git-svn-id: svn://localhost/ardour2/trunk@1981 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
0605f98fdc
commit
7ff7f4013d
@ -150,12 +150,11 @@ MidiRegionView::end_write()
|
|||||||
void
|
void
|
||||||
MidiRegionView::add_event (const MidiEvent& ev)
|
MidiRegionView::add_event (const MidiEvent& ev)
|
||||||
{
|
{
|
||||||
printf("Event, time = %u, size = %zu, data = ",
|
printf("Event, time = %f, size = %zu, data = ", ev.time, ev.size);
|
||||||
ev.time, ev.size);
|
for (size_t i=0; i < ev.size; ++i) {
|
||||||
for (size_t i=0; i < ev.size; ++i) {
|
printf("%X ", ev.buffer[i]);
|
||||||
printf("%X ", ev.buffer[i]);
|
}
|
||||||
}
|
printf("\n\n");
|
||||||
printf("\n\n");
|
|
||||||
|
|
||||||
double y1 = trackview.height / 2.0;
|
double y1 = trackview.height / 2.0;
|
||||||
if ((ev.buffer[0] & 0xF0) == MIDI_CMD_NOTE_ON) {
|
if ((ev.buffer[0] & 0xF0) == MIDI_CMD_NOTE_ON) {
|
||||||
@ -165,7 +164,7 @@ MidiRegionView::add_event (const MidiEvent& ev)
|
|||||||
ArdourCanvas::SimpleRect * ev_rect = new Gnome::Canvas::SimpleRect(
|
ArdourCanvas::SimpleRect * ev_rect = new Gnome::Canvas::SimpleRect(
|
||||||
*(ArdourCanvas::Group*)get_canvas_group());
|
*(ArdourCanvas::Group*)get_canvas_group());
|
||||||
ev_rect->property_x1() = trackview.editor.frame_to_pixel (
|
ev_rect->property_x1() = trackview.editor.frame_to_pixel (
|
||||||
ev.time);
|
(nframes_t)ev.time);
|
||||||
ev_rect->property_y1() = y1;
|
ev_rect->property_y1() = y1;
|
||||||
ev_rect->property_x2() = trackview.editor.frame_to_pixel (
|
ev_rect->property_x2() = trackview.editor.frame_to_pixel (
|
||||||
_region->length());
|
_region->length());
|
||||||
@ -182,7 +181,7 @@ MidiRegionView::add_event (const MidiEvent& ev)
|
|||||||
} else if ((ev.buffer[0] & 0xF0) == MIDI_CMD_NOTE_OFF) {
|
} else if ((ev.buffer[0] & 0xF0) == MIDI_CMD_NOTE_OFF) {
|
||||||
const Byte& note = ev.buffer[1];
|
const Byte& note = ev.buffer[1];
|
||||||
if (_active_notes && _active_notes[note]) {
|
if (_active_notes && _active_notes[note]) {
|
||||||
_active_notes[note]->property_x2() = trackview.editor.frame_to_pixel(ev.time);
|
_active_notes[note]->property_x2() = trackview.editor.frame_to_pixel((nframes_t)ev.time);
|
||||||
_active_notes[note]->property_outline_what() = (guint32) 0xF; // all edges
|
_active_notes[note]->property_outline_what() = (guint32) 0xF; // all edges
|
||||||
_active_notes[note] = NULL;
|
_active_notes[note] = NULL;
|
||||||
}
|
}
|
||||||
|
@ -190,7 +190,8 @@ public:
|
|||||||
void read_from(const Buffer& src, nframes_t nframes, nframes_t offset);
|
void read_from(const Buffer& src, nframes_t nframes, nframes_t offset);
|
||||||
|
|
||||||
bool push_back(const ARDOUR::MidiEvent& event);
|
bool push_back(const ARDOUR::MidiEvent& event);
|
||||||
Byte* reserve(nframes_t time, size_t size);
|
bool push_back(const jack_midi_event_t& event);
|
||||||
|
Byte* reserve(double time, size_t size);
|
||||||
|
|
||||||
const MidiEvent& operator[](size_t i) const { assert(i < _size); return _events[i]; }
|
const MidiEvent& operator[](size_t i) const { assert(i < _size); return _events[i]; }
|
||||||
MidiEvent& operator[](size_t i) { assert(i < _size); return _events[i]; }
|
MidiEvent& operator[](size_t i) { assert(i < _size); return _events[i]; }
|
||||||
|
@ -41,7 +41,7 @@ public:
|
|||||||
void append(const MidiBuffer& data);
|
void append(const MidiBuffer& data);
|
||||||
|
|
||||||
/** Resizes vector if necessary (NOT realtime safe) */
|
/** Resizes vector if necessary (NOT realtime safe) */
|
||||||
void append(const MidiEvent& ev);
|
void append(double time, size_t size, Byte* in_buffer);
|
||||||
|
|
||||||
inline const MidiEvent& event_at(unsigned i) const { return _events[i]; }
|
inline const MidiEvent& event_at(unsigned i) const { return _events[i]; }
|
||||||
|
|
||||||
|
@ -26,6 +26,9 @@
|
|||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
|
|
||||||
|
/* FIXME: this is probably too much inlined code */
|
||||||
|
|
||||||
|
|
||||||
/** A RingBuffer.
|
/** A RingBuffer.
|
||||||
* Read/Write realtime safe.
|
* Read/Write realtime safe.
|
||||||
* Single-reader Single-writer thread safe.
|
* Single-reader Single-writer thread safe.
|
||||||
@ -226,17 +229,17 @@ public:
|
|||||||
: MidiRingBufferBase<Byte>(size)
|
: MidiRingBufferBase<Byte>(size)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
size_t write(nframes_t time, size_t size, const Byte* buf);
|
size_t write(double time, size_t size, const Byte* buf);
|
||||||
bool read(nframes_t time, size_t* size, Byte* buf);
|
bool read(double* time, size_t* size, Byte* buf);
|
||||||
|
|
||||||
size_t read(MidiBuffer& dst, nframes_t start, nframes_t end);
|
size_t read(MidiBuffer& dst, nframes_t start, nframes_t end);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
MidiRingBuffer::read(nframes_t time, size_t* size, Byte* buf)
|
MidiRingBuffer::read(double* time, size_t* size, Byte* buf)
|
||||||
{
|
{
|
||||||
bool success = MidiRingBufferBase<Byte>::full_read(sizeof(nframes_t), (Byte*)time);
|
bool success = MidiRingBufferBase<Byte>::full_read(sizeof(double), (Byte*)time);
|
||||||
if (success)
|
if (success)
|
||||||
success = MidiRingBufferBase<Byte>::full_read(sizeof(size_t), (Byte*)size);
|
success = MidiRingBufferBase<Byte>::full_read(sizeof(size_t), (Byte*)size);
|
||||||
if (success)
|
if (success)
|
||||||
@ -247,14 +250,14 @@ MidiRingBuffer::read(nframes_t time, size_t* size, Byte* buf)
|
|||||||
|
|
||||||
|
|
||||||
inline size_t
|
inline size_t
|
||||||
MidiRingBuffer::write(nframes_t time, size_t size, const Byte* buf)
|
MidiRingBuffer::write(double time, size_t size, const Byte* buf)
|
||||||
{
|
{
|
||||||
assert(size > 0);
|
assert(size > 0);
|
||||||
|
|
||||||
if (write_space() < (sizeof(nframes_t) + sizeof(size_t) + size)) {
|
if (write_space() < (sizeof(double) + sizeof(size_t) + size)) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
MidiRingBufferBase<Byte>::write(sizeof(nframes_t), (Byte*)&time);
|
MidiRingBufferBase<Byte>::write(sizeof(double), (Byte*)&time);
|
||||||
MidiRingBufferBase<Byte>::write(sizeof(size_t), (Byte*)&size);
|
MidiRingBufferBase<Byte>::write(sizeof(size_t), (Byte*)&size);
|
||||||
MidiRingBufferBase<Byte>::write(size, buf);
|
MidiRingBufferBase<Byte>::write(size, buf);
|
||||||
return size;
|
return size;
|
||||||
@ -262,6 +265,11 @@ MidiRingBuffer::write(nframes_t time, size_t size, const Byte* buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Read a block of MIDI events from buffer.
|
||||||
|
*
|
||||||
|
* Timestamps of events returned are relative to start (ie event with stamp 0
|
||||||
|
* occurred at start).
|
||||||
|
*/
|
||||||
inline size_t
|
inline size_t
|
||||||
MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end)
|
MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end)
|
||||||
{
|
{
|
||||||
@ -272,14 +280,14 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end)
|
|||||||
|
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
|
|
||||||
while (read_space() > sizeof(nframes_t) + sizeof(size_t)) {
|
while (read_space() > sizeof(double) + sizeof(size_t)) {
|
||||||
|
|
||||||
full_peek(sizeof(nframes_t), (Byte*)&ev.time);
|
full_peek(sizeof(double), (Byte*)&ev.time);
|
||||||
|
|
||||||
if (ev.time > end)
|
if (ev.time > end)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
bool success = MidiRingBufferBase<Byte>::full_read(sizeof(nframes_t), (Byte*)&ev.time);
|
bool success = MidiRingBufferBase<Byte>::full_read(sizeof(double), (Byte*)&ev.time);
|
||||||
if (success)
|
if (success)
|
||||||
success = MidiRingBufferBase<Byte>::full_read(sizeof(size_t), (Byte*)&ev.size);
|
success = MidiRingBufferBase<Byte>::full_read(sizeof(size_t), (Byte*)&ev.size);
|
||||||
|
|
||||||
@ -300,13 +308,14 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end)
|
|||||||
// priv_read_ptr);
|
// priv_read_ptr);
|
||||||
//
|
//
|
||||||
} else {
|
} else {
|
||||||
printf("MRB - SKIPPING EVENT (with time %u)\n", ev.time);
|
printf("MRB - SKIPPING EVENT (with time %f)\n", ev.time);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
++count;
|
++count;
|
||||||
|
|
||||||
assert(ev.time <= end);
|
assert(ev.time <= end);
|
||||||
|
ev.time -= start;
|
||||||
}
|
}
|
||||||
|
|
||||||
//printf("(R) read space: %zu\n", read_space());
|
//printf("(R) read space: %zu\n", read_space());
|
||||||
|
@ -110,7 +110,7 @@ class SMFSource : public MidiSource {
|
|||||||
void write_chunk(char id[4], uint32_t length, void* data);
|
void write_chunk(char id[4], uint32_t length, void* data);
|
||||||
size_t write_var_len(uint32_t val);
|
size_t write_var_len(uint32_t val);
|
||||||
uint32_t read_var_len() const;
|
uint32_t read_var_len() const;
|
||||||
int read_event(MidiEvent& ev) const;
|
int read_event(jack_midi_event_t& ev) const;
|
||||||
|
|
||||||
static const uint16_t _ppqn = 19200;
|
static const uint16_t _ppqn = 19200;
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ class SMFSource : public MidiSource {
|
|||||||
bool _allow_remove_if_empty;
|
bool _allow_remove_if_empty;
|
||||||
uint64_t _timeline_position;
|
uint64_t _timeline_position;
|
||||||
FILE* _fd;
|
FILE* _fd;
|
||||||
nframes_t _last_ev_time; // last frame time written, relative to source start
|
double _last_ev_time; // last frame time written, relative to source start
|
||||||
uint32_t _track_size;
|
uint32_t _track_size;
|
||||||
uint32_t _header_size; // size of SMF header, including MTrk chunk header
|
uint32_t _header_size; // size of SMF header, including MTrk chunk header
|
||||||
|
|
||||||
|
@ -61,8 +61,19 @@ namespace ARDOUR {
|
|||||||
|
|
||||||
typedef unsigned char Byte;
|
typedef unsigned char Byte;
|
||||||
|
|
||||||
struct MidiEvent : public jack_midi_event_t {
|
/** Identical to jack_midi_event_t, but with double timestamp
|
||||||
MidiEvent() { time = 0; size = 0; buffer = NULL; }
|
*
|
||||||
|
* time is either a frame time (from/to Jack) or a beat time (internal
|
||||||
|
* tempo time, used in MidiModel) depending on context.
|
||||||
|
*/
|
||||||
|
struct MidiEvent {
|
||||||
|
MidiEvent(double t=0, size_t s=0, Byte* b=NULL)
|
||||||
|
: time(t), size(s), buffer(b)
|
||||||
|
{}
|
||||||
|
|
||||||
|
double time; /**< Sample index (or beat time) at which event is valid */
|
||||||
|
size_t size; /**< Number of bytes of data in \a buffer */
|
||||||
|
Byte* buffer; /**< Raw MIDI data */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum IOChange {
|
enum IOChange {
|
||||||
|
@ -153,6 +153,35 @@ MidiBuffer::push_back(const MidiEvent& ev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Push an event into the buffer.
|
||||||
|
*
|
||||||
|
* Note that the raw MIDI pointed to by ev will be COPIED and unmodified.
|
||||||
|
* That is, the caller still owns it, if it needs freeing it's Not My Problem(TM).
|
||||||
|
* Realtime safe.
|
||||||
|
* @return false if operation failed (not enough room)
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
MidiBuffer::push_back(const jack_midi_event_t& ev)
|
||||||
|
{
|
||||||
|
if (_size == _capacity)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Byte* const write_loc = _data + (_size * MAX_EVENT_SIZE);
|
||||||
|
|
||||||
|
memcpy(write_loc, ev.buffer, ev.size);
|
||||||
|
_events[_size].time = (double)ev.time;
|
||||||
|
_events[_size].size = ev.size;
|
||||||
|
_events[_size].buffer = write_loc;
|
||||||
|
++_size;
|
||||||
|
|
||||||
|
//cerr << "MidiBuffer: pushed, size = " << _size << endl;
|
||||||
|
|
||||||
|
_silent = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Reserve space for a new event in the buffer.
|
/** Reserve space for a new event in the buffer.
|
||||||
*
|
*
|
||||||
* This call is for copying MIDI directly into the buffer, the data location
|
* This call is for copying MIDI directly into the buffer, the data location
|
||||||
@ -161,7 +190,7 @@ MidiBuffer::push_back(const MidiEvent& ev)
|
|||||||
* location, or the buffer will be corrupted and very nasty things will happen.
|
* location, or the buffer will be corrupted and very nasty things will happen.
|
||||||
*/
|
*/
|
||||||
Byte*
|
Byte*
|
||||||
MidiBuffer::reserve(nframes_t time, size_t size)
|
MidiBuffer::reserve(double time, size_t size)
|
||||||
{
|
{
|
||||||
assert(size < MAX_EVENT_SIZE);
|
assert(size < MAX_EVENT_SIZE);
|
||||||
|
|
||||||
|
@ -1471,44 +1471,10 @@ MidiDiskstream::get_playback(MidiBuffer& dst, nframes_t start, nframes_t end)
|
|||||||
|
|
||||||
// I think this happens with reverse varispeed? maybe?
|
// I think this happens with reverse varispeed? maybe?
|
||||||
if (end <= start) {
|
if (end <= start) {
|
||||||
|
cerr << "MDS: Reverse? Skipping" << endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Translates stamps to be relative to start
|
||||||
cerr << "MIDI Diskstream pretending to read" << endl;
|
|
||||||
|
|
||||||
MidiEvent ev;
|
|
||||||
Byte data[4];
|
|
||||||
|
|
||||||
const char note = rand()%30 + 30;
|
|
||||||
|
|
||||||
ev.buffer = data;
|
|
||||||
ev.time = 0;
|
|
||||||
ev.size = 3;
|
|
||||||
|
|
||||||
data[0] = 0x90;
|
|
||||||
data[1] = note;
|
|
||||||
data[2] = 120;
|
|
||||||
|
|
||||||
dst.push_back(ev);
|
|
||||||
|
|
||||||
ev.buffer = data;
|
|
||||||
ev.time = (end - start) / 2;
|
|
||||||
ev.size = 3;
|
|
||||||
|
|
||||||
data[0] = 0x80;
|
|
||||||
data[1] = note;
|
|
||||||
data[2] = 64;
|
|
||||||
*/
|
|
||||||
_playback_buf->read(dst, start, end);
|
_playback_buf->read(dst, start, end);
|
||||||
|
|
||||||
// Translate time stamps to be relative to the start of this cycle
|
|
||||||
for (size_t i=0; i < dst.size(); ++i) {
|
|
||||||
assert(dst[i].time >= start);
|
|
||||||
assert(dst[i].time <= end);
|
|
||||||
//cerr << "Translating event stamp " << dst[i].time << " to ";
|
|
||||||
dst[i].time -= start;
|
|
||||||
//cerr << dst[i].time << endl;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ MidiModel::~MidiModel()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Append contents of \a buf to model. NOT (even remotely) realtime safe.
|
/** Append contents of \a buf to model. NOT realtime safe.
|
||||||
*
|
*
|
||||||
* Timestamps of events in \a buf are expected to be relative to
|
* Timestamps of events in \a buf are expected to be relative to
|
||||||
* the start of this model (t=0) and MUST be monotonically increasing
|
* the start of this model (t=0) and MUST be monotonically increasing
|
||||||
@ -64,25 +64,21 @@ MidiModel::append(const MidiBuffer& buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Append \a in_event to model. NOT (even remotely) realtime safe.
|
/** Append \a in_event to model. NOT realtime safe.
|
||||||
*
|
*
|
||||||
* Timestamps of events in \a buf are expected to be relative to
|
* Timestamps of events in \a buf are expected to be relative to
|
||||||
* the start of this model (t=0) and MUST be monotonically increasing
|
* the start of this model (t=0) and MUST be monotonically increasing
|
||||||
* and MUST be >= the latest event currently in the model.
|
* and MUST be >= the latest event currently in the model.
|
||||||
*
|
|
||||||
* Events in buf are deep copied.
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
MidiModel::append(const MidiEvent& in_event)
|
MidiModel::append(double time, size_t size, Byte* in_buffer)
|
||||||
{
|
{
|
||||||
assert(_events.empty() || in_event.time >= _events.back().time);
|
assert(_events.empty() || time >= _events.back().time);
|
||||||
|
|
||||||
_events.push_back(in_event);
|
cerr << "Model event: time = " << time << endl;
|
||||||
MidiEvent& my_event = _events.back();
|
|
||||||
assert(my_event.time == in_event.time);
|
|
||||||
assert(my_event.size == in_event.size);
|
|
||||||
|
|
||||||
my_event.buffer = new Byte[my_event.size];
|
Byte* my_buffer = new Byte[size];
|
||||||
memcpy(my_event.buffer, in_event.buffer, my_event.size);
|
memcpy(my_buffer, in_buffer, size);
|
||||||
|
_events.push_back(MidiEvent(time, size, my_buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,19 +66,13 @@ MidiPort::cycle_start (nframes_t nframes)
|
|||||||
|
|
||||||
assert(event_count < _buffer.capacity());
|
assert(event_count < _buffer.capacity());
|
||||||
|
|
||||||
MidiEvent ev;
|
jack_midi_event_t ev;
|
||||||
|
|
||||||
// FIXME: too slow, event struct is copied twice (here and MidiBuffer::push_back)
|
|
||||||
for (nframes_t i=0; i < event_count; ++i) {
|
for (nframes_t i=0; i < event_count; ++i) {
|
||||||
|
|
||||||
// This will fail to compile if we change MidiEvent to our own class
|
jack_midi_event_get(&ev, jack_buffer, i);
|
||||||
jack_midi_event_get(static_cast<jack_midi_event_t*>(&ev), jack_buffer, i);
|
|
||||||
|
|
||||||
_buffer.push_back(ev);
|
_buffer.push_back(ev);
|
||||||
// Convert note ons with velocity 0 to proper note offs
|
|
||||||
// FIXME: Jack MIDI should guarantee this - does it?
|
|
||||||
//if (ev->buffer[0] == MIDI_CMD_NOTE_ON && ev->buffer[2] == 0)
|
|
||||||
// ev->buffer[0] = MIDI_CMD_NOTE_OFF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(_buffer.size() == event_count);
|
assert(_buffer.size() == event_count);
|
||||||
@ -106,9 +100,11 @@ MidiPort::cycle_end()
|
|||||||
|
|
||||||
jack_midi_clear_buffer(jack_buffer);
|
jack_midi_clear_buffer(jack_buffer);
|
||||||
for (nframes_t i=0; i < event_count; ++i) {
|
for (nframes_t i=0; i < event_count; ++i) {
|
||||||
const jack_midi_event_t& ev = _buffer[i];
|
const MidiEvent& ev = _buffer[i];
|
||||||
|
// event times should be frames, relative to cycle start
|
||||||
|
assert(ev.time >= 0);
|
||||||
assert(ev.time < _nframes_this_cycle);
|
assert(ev.time < _nframes_this_cycle);
|
||||||
jack_midi_event_write(jack_buffer, ev.time, ev.buffer, ev.size);
|
jack_midi_event_write(jack_buffer, (jack_nframes_t)ev.time, ev.buffer, ev.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
_nframes_this_cycle = 0;
|
_nframes_this_cycle = 0;
|
||||||
|
@ -250,7 +250,7 @@ SMFSource::find_first_event_after(nframes_t start)
|
|||||||
* skipped (eg a meta event), or -1 on EOF (or end of track).
|
* skipped (eg a meta event), or -1 on EOF (or end of track).
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
SMFSource::read_event(MidiEvent& ev) const
|
SMFSource::read_event(jack_midi_event_t& ev) const
|
||||||
{
|
{
|
||||||
// - 4 is for the EOT event, which we don't actually want to read
|
// - 4 is for the EOT event, which we don't actually want to read
|
||||||
//if (feof(_fd) || ftell(_fd) >= _header_size + _track_size - 4) {
|
//if (feof(_fd) || ftell(_fd) >= _header_size + _track_size - 4) {
|
||||||
@ -307,13 +307,12 @@ SMFSource::read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, n
|
|||||||
|
|
||||||
// FIXME: ugh
|
// FIXME: ugh
|
||||||
unsigned char ev_buf[MidiBuffer::max_event_size()];
|
unsigned char ev_buf[MidiBuffer::max_event_size()];
|
||||||
MidiEvent ev;
|
jack_midi_event_t ev; // time in SMF ticks
|
||||||
ev.time = 0;
|
ev.time = 0;
|
||||||
ev.size = MidiBuffer::max_event_size();
|
ev.size = MidiBuffer::max_event_size();
|
||||||
ev.buffer = ev_buf;
|
ev.buffer = ev_buf;
|
||||||
|
|
||||||
// FIXME: it would be an impressive feat to actually make this any slower :)
|
// FIXME: don't seek to start every read
|
||||||
|
|
||||||
fseek(_fd, _header_size, 0);
|
fseek(_fd, _header_size, 0);
|
||||||
|
|
||||||
// FIXME: assumes tempo never changes after start
|
// FIXME: assumes tempo never changes after start
|
||||||
@ -787,8 +786,11 @@ SMFSource::load_model(bool lock)
|
|||||||
|
|
||||||
fseek(_fd, _header_size, 0);
|
fseek(_fd, _header_size, 0);
|
||||||
|
|
||||||
nframes_t time = 0;
|
uint64_t time = 0; /* in SMF ticks */
|
||||||
MidiEvent ev;
|
jack_midi_event_t ev;
|
||||||
|
ev.time = 0;
|
||||||
|
ev.size = 0;
|
||||||
|
ev.buffer = NULL;
|
||||||
|
|
||||||
// FIXME: assumes tempo never changes after start
|
// FIXME: assumes tempo never changes after start
|
||||||
const double frames_per_beat = _session.tempo_map().tempo_at(_timeline_position).frames_per_beat(
|
const double frames_per_beat = _session.tempo_map().tempo_at(_timeline_position).frames_per_beat(
|
||||||
@ -797,13 +799,12 @@ SMFSource::load_model(bool lock)
|
|||||||
int ret;
|
int ret;
|
||||||
while ((ret = read_event(ev)) >= 0) {
|
while ((ret = read_event(ev)) >= 0) {
|
||||||
time += ev.time;
|
time += ev.time;
|
||||||
ev.time = time;
|
|
||||||
|
|
||||||
ev.time = (nframes_t)(ev.time * frames_per_beat / (double)_ppqn);
|
const double ev_time = (double)(time * frames_per_beat / (double)_ppqn); // in frames
|
||||||
|
|
||||||
if (ret > 0) { // didn't skip (meta) event
|
if (ret > 0) { // didn't skip (meta) event
|
||||||
//cerr << "ADDING EVENT TO MODEL: " << ev.time << endl;
|
//cerr << "ADDING EVENT TO MODEL: " << ev.time << endl;
|
||||||
_model->append(ev);
|
_model->append(ev_time, ev.size, ev.buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user