X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fsmf_source.cc;h=730ba053bd6df8a4922bcc849f6d67ee121e691e;hb=ca40990444b09d1de532c572793ab702840714f7;hp=aca8cf5a2576d5d0bfbe8b0e5ced87eba9a8c7cd;hpb=532f6aad4ac79ca15d69deccd18fca90e444c437;p=ardour.git diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc index aca8cf5a25..730ba053bd 100644 --- a/libs/ardour/smf_source.cc +++ b/libs/ardour/smf_source.cc @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include "i18n.h" @@ -147,7 +149,7 @@ SMFSource::open() uint32_t track_size_be = 0; fread(&track_size_be, 4, 1, _fd); _track_size = GUINT32_FROM_BE(track_size_be); - cerr << "SMF - read track size " << _track_size; + cerr << "SMF - read track size " << _track_size << endl; // We're making a new file } else { @@ -163,7 +165,7 @@ SMFSource::open() } int -SMFSource::update_header (jack_nframes_t when, struct tm&, time_t) +SMFSource::update_header (nframes_t when, struct tm&, time_t) { _timeline_position = when; return flush_header(); @@ -178,9 +180,9 @@ SMFSource::flush_header () assert(_fd); - const uint16_t type = GUINT16_TO_BE(0); // SMF Type 0 (single track) - const uint16_t ntracks = GUINT16_TO_BE(1); // Number of tracks (always 1 for Type 0) - const uint16_t division = GUINT16_TO_BE(1920); // FIXME FIXME FIXME PPQN + const uint16_t type = GUINT16_TO_BE(0); // SMF Type 0 (single track) + const uint16_t ntracks = GUINT16_TO_BE(1); // Number of tracks (always 1 for Type 0) + const uint16_t division = GUINT16_TO_BE(_ppqn); // Pulses per beat char data[6]; memcpy(data, &type, 2); @@ -220,7 +222,7 @@ SMFSource::flush_footer() */ /* long -SMFSource::find_first_event_after(jack_nframes_t start) +SMFSource::find_first_event_after(nframes_t start) { // FIXME: obviously this is slooow @@ -241,8 +243,8 @@ SMFSource::find_first_event_after(jack_nframes_t start) * * File position MUST be at the beginning of a delta time, or this will die very messily. * ev.buffer must be of size ev.size, and large enough for the event. The returned event - * will have it's time field set to it's delta time (so it's the caller's responsibility - * to calculate a real time for the event). + * will have it's time field set to it's delta time, in SMF tempo-based ticks, using the + * rate given by ppqn() (it is the caller's responsibility to calculate a real time). * * Returns event length (including status byte) on success, 0 if event was * skipped (eg a meta event), or -1 on EOF (or end of track). @@ -287,12 +289,16 @@ SMFSource::read_event(MidiEvent& ev) const return ev.size; } -jack_nframes_t -SMFSource::read_unlocked (MidiRingBuffer& dst, jack_nframes_t start, jack_nframes_t cnt, jack_nframes_t stamp_offset) const +/** All stamps in audio frames */ +nframes_t +SMFSource::read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset) const { //cerr << "SMF - read " << start << ", count=" << cnt << ", offset=" << stamp_offset << endl; - jack_nframes_t time = 0; + // 64 bits ought to be enough for anybody + uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn + + _read_data_count = 0; // FIXME: ugh unsigned char ev_buf[MidiBuffer::max_event_size()]; @@ -305,6 +311,12 @@ SMFSource::read_unlocked (MidiRingBuffer& dst, jack_nframes_t start, jack_nframe fseek(_fd, _header_size, 0); + // FIXME: assumes tempo never changes after start + const double frames_per_beat = _session.tempo_map().tempo_at(_timeline_position).frames_per_beat( + _session.engine().frame_rate()); + + uint64_t start_ticks = (uint64_t)((start / frames_per_beat) * _ppqn); + while (!feof(_fd)) { int ret = read_event(ev); if (ret == -1) { // EOF @@ -321,35 +333,44 @@ SMFSource::read_unlocked (MidiRingBuffer& dst, jack_nframes_t start, jack_nframe time += ev.time; // accumulate delta time ev.time = time; // set ev.time to actual time (relative to source start) - if (ev.time >= start) { - if (ev.time > start + cnt) { + if (ev.time >= start_ticks) { + if (ev.time < start_ticks + (cnt / frames_per_beat)) { break; } else { - ev.time += stamp_offset; - dst.write(ev); + ev.time = (nframes_t)(((ev.time / (double)_ppqn) * frames_per_beat)) + stamp_offset; + // write event time in absolute frames + dst.write(ev.time, ev.size, ev.buffer); } } + + _read_data_count += ev.size; } return cnt; } -jack_nframes_t -SMFSource::write_unlocked (MidiRingBuffer& src, jack_nframes_t cnt) +/** All stamps in audio frames */ +nframes_t +SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt) { - //cerr << "SMF WRITE -- " << _length << "--" << cnt << endl; - - MidiBuffer buf(1024); // FIXME: allocation, size? + _write_data_count = 0; + + boost::shared_ptr buf_ptr(new MidiBuffer(1024)); // FIXME: size? + MidiBuffer& buf = *buf_ptr.get(); src.read(buf, /*_length*/0, _length + cnt); // FIXME? fseek(_fd, 0, SEEK_END); - // FIXME: start of source time? + // FIXME: assumes tempo never changes after start + const double frames_per_beat = _session.tempo_map().tempo_at(_timeline_position).frames_per_beat( + _session.engine().frame_rate()); for (size_t i=0; i < buf.size(); ++i) { - const MidiEvent& ev = buf[i]; + MidiEvent& ev = buf[i]; assert(ev.time >= _timeline_position); - uint32_t delta_time = (ev.time - _timeline_position) - _last_ev_time; + ev.time -= _timeline_position; + assert(ev.time >= _last_ev_time); + const uint32_t delta_time = (uint32_t)((ev.time - _last_ev_time) / frames_per_beat * _ppqn); /*printf("SMF - writing event, delta = %u, size = %zu, data = ", delta_time, ev.size); @@ -360,17 +381,22 @@ SMFSource::write_unlocked (MidiRingBuffer& src, jack_nframes_t cnt) */ size_t stamp_size = write_var_len(delta_time); fwrite(ev.buffer, 1, ev.size, _fd); - _last_ev_time += delta_time; + _track_size += stamp_size + ev.size; + _write_data_count += ev.size; + + _last_ev_time = ev.time; } fflush(_fd); - if (buf.size() > 0) { - ViewDataRangeReady (_length, cnt); /* EMIT SIGNAL */ - } + const nframes_t oldlen = _length; + update_length(oldlen, cnt); - update_length(_length, cnt); + _model.append(buf); + + ViewDataRangeReady (buf_ptr, oldlen, cnt); /* EMIT SIGNAL */ + return cnt; } @@ -744,3 +770,33 @@ SMFSource::read_var_len() const return value; } + +void +SMFSource::load_model(bool lock) +{ + if (lock) + Glib::Mutex::Lock lm (_lock); + + _model.clear(); + + fseek(_fd, _header_size, 0); + + nframes_t time = 0; + MidiEvent ev; + + int ret; + while ((ret = read_event(ev)) >= 0) { + time += ev.time; + ev.time = time; + if (ret > 0) { // didn't skip (meta) event + _model.append(ev); + } + } +} + +void +SMFSource::destroy_model() +{ + _model.clear(); +} +