diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/SMFReader.cpp | 10 | ||||
-rw-r--r-- | src/SMFWriter.cpp | 47 | ||||
-rw-r--r-- | src/TimeSlice.cpp | 2 |
3 files changed, 38 insertions, 21 deletions
diff --git a/src/SMFReader.cpp b/src/SMFReader.cpp index a27939d..c21058b 100644 --- a/src/SMFReader.cpp +++ b/src/SMFReader.cpp @@ -72,6 +72,7 @@ midi_event_size(unsigned char status) SMFReader::SMFReader() : _fd(NULL) + , _unit(TimeUnit::BEATS, 192) , _ppqn(0) , _track(0) , _track_size(0) @@ -126,6 +127,7 @@ SMFReader::open(const string& filename) uint16_t ppqn_be = 0; fread(&ppqn_be, 2, 1, _fd); _ppqn = GUINT16_FROM_BE(ppqn_be); + _unit = TimeUnit::beats(_ppqn); seek_to_track(1); @@ -198,10 +200,10 @@ SMFReader::seek_to_track(unsigned track) throw (std::logic_error) * set to the actual size of the event. */ int -SMFReader::read_event(size_t buf_len, - uint8_t* buf, - uint32_t* ev_size, - uint32_t* delta_time) throw (std::logic_error) +SMFReader::read_event(size_t buf_len, + uint8_t* buf, + uint32_t* ev_size, + TimeStamp* delta_time) throw (std::logic_error) { if (_track == 0) throw logic_error("Attempt to read from unopened SMF file"); diff --git a/src/SMFWriter.cpp b/src/SMFWriter.cpp index b141e30..4ea65b0 100644 --- a/src/SMFWriter.cpp +++ b/src/SMFWriter.cpp @@ -15,7 +15,8 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <cstdio> +#include <stdint.h> +#include <cassert> #include <iostream> #include <glibmm/miscutils.h> #include <raul/SMFWriter.hpp> @@ -25,13 +26,23 @@ using namespace std; namespace Raul { -SMFWriter::SMFWriter(unsigned short ppqn) +/** Create a new SMF writer. + * + * @a unit must match the time stamp of ALL events passed to write, or + * terrible things will happen. + * + * *** NOTE: Only beat time is implemented currently. + */ +SMFWriter::SMFWriter(TimeUnit unit) : _fd(NULL) - , _ppqn(ppqn) - , _last_ev_time(0) + , _unit(unit) + , _start_time(unit, 0, 0) + , _last_ev_time(unit, 0, 0) , _track_size(0) , _header_size(0) { + if (unit.type() == TimeUnit::BEATS) + assert(unit.ppt() < std::numeric_limits<uint16_t>::max()); } @@ -49,8 +60,8 @@ SMFWriter::~SMFWriter() * to write_event will have this value subtracted before writing). */ bool -SMFWriter::start(const string& filename, - Raul::BeatTime start_time) throw (logic_error) +SMFWriter::start(const string& filename, + Raul::TimeStamp start_time) throw (logic_error) { if (_fd) throw logic_error("Attempt to start new write while write in progress."); @@ -79,7 +90,7 @@ SMFWriter::start(const string& filename, * successive calls to this method. */ void -SMFWriter::write_event(Raul::BeatTime time, +SMFWriter::write_event(Raul::TimeStamp time, size_t ev_size, const unsigned char* ev) throw (logic_error) { @@ -87,27 +98,31 @@ SMFWriter::write_event(Raul::BeatTime time, throw logic_error("Event time is before file start time"); else if (time < _last_ev_time) throw logic_error("Event time not monotonically increasing"); + else if (time.unit() != _unit) + throw logic_error("Event has unexpected time unit"); - time -= _start_time; + Raul::TimeStamp delta_time = time; + delta_time -= _start_time; fseek(_fd, 0, SEEK_END); - double delta_time = (time - _last_ev_time) / (double)_ppqn; + uint64_t delta_ticks = delta_time.ticks() * _unit.ppt() + delta_time.subticks(); size_t stamp_size = 0; /* If delta time is too long (i.e. overflows), write out empty * "proprietary" events to reach the desired time. * Any SMF reading application should interpret this correctly * (by accumulating the delta time and ignoring the event) */ - while (delta_time > VAR_LEN_MAX) { + while (delta_ticks > VAR_LEN_MAX) { static unsigned char null_event[] = { 0xFF, 0x7F, 0x0 }; stamp_size = write_var_len(VAR_LEN_MAX); fwrite(null_event, 1, 3, _fd); - delta_time -= VAR_LEN_MAX; + _track_size += stamp_size + 3; + delta_ticks -= VAR_LEN_MAX; } - assert(delta_time < VAR_LEN_MAX); - stamp_size = write_var_len((uint32_t)delta_time); + assert(delta_ticks <= VAR_LEN_MAX); + stamp_size = write_var_len((uint32_t)delta_ticks); fwrite(ev, 1, ev_size, _fd); _last_ev_time = time; @@ -142,9 +157,9 @@ SMFWriter::write_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(_ppqn); // Number of tracks (always 1 for Type 0) + 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(_unit.ppt()); // PPQN char data[6]; memcpy(data, &type, 2); diff --git a/src/TimeSlice.cpp b/src/TimeSlice.cpp index e983a33..bfc2f66 100644 --- a/src/TimeSlice.cpp +++ b/src/TimeSlice.cpp @@ -20,7 +20,7 @@ namespace Raul { -TimeSlice::TimeSlice(double tick_rate, double bpm) +TimeSlice::TimeSlice(uint32_t tick_rate, double bpm) : _tick_rate(tick_rate) , _beat_rate(60.0/bpm) , _start_ticks(0) |