namespace Evoral {
-template<typename T>
-SMF<T>::SMF()
+template<typename Time>
+SMF<Time>::SMF()
: _fd(0)
, _last_ev_time(0)
, _track_size(4) // 4 bytes for the ever-present EOT event
{
}
-template<typename T>
-SMF<T>::~SMF()
+template<typename Time>
+SMF<Time>::~SMF()
{
}
* -1 if the file can not be opened for reading,
* -2 if the file can not be opened for writing
*/
-template<typename T>
+template<typename Time>
int
-SMF<T>::open(const std::string& path)
+SMF<Time>::open(const std::string& path) THROW_FILE_ERROR
+
{
//cerr << "Opening SMF file " << path() << " writeable: " << writable() << endl;
_fd = fopen(path.c_str(), "r+");
return (_fd == 0) ? -1 : 0;
}
-template<typename T>
+template<typename Time>
void
-SMF<T>::close()
+SMF<Time>::close() THROW_FILE_ERROR
{
if (_fd) {
flush_header();
}
}
-template<typename T>
+template<typename Time>
void
-SMF<T>::seek_to_start() const
+SMF<Time>::seek_to_start() const
{
fseek(_fd, _header_size, SEEK_SET);
}
-template<typename T>
+template<typename Time>
void
-SMF<T>::seek_to_footer_position()
+SMF<Time>::seek_to_footer_position()
{
uint8_t buffer[4];
}
}
-template<typename T>
+template<typename Time>
void
-SMF<T>::flush()
+SMF<Time>::flush()
{
fflush(_fd);
}
-template<typename T>
+template<typename Time>
int
-SMF<T>::flush_header()
+SMF<Time>::flush_header()
{
// FIXME: write timeline position somehow?
return 0;
}
-template<typename T>
+template<typename Time>
int
-SMF<T>::flush_footer()
+SMF<Time>::flush_footer()
{
//cerr << path() << " SMF Flushing footer\n";
seek_to_footer_position();
return 0;
}
-template<typename T>
+template<typename Time>
void
-SMF<T>::write_footer()
+SMF<Time>::write_footer()
{
write_var_len(0);
char eot[3] = { 0xFF, 0x2F, 0x00 }; // end-of-track meta-event
* 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).
*/
-template<typename T>
+template<typename Time>
int
-SMF<T>::read_event(uint32_t* delta_t, uint32_t* size, uint8_t** buf) const
+SMF<Time>::read_event(uint32_t* delta_t, uint32_t* size, uint8_t** buf) const
{
if (feof(_fd)) {
return -1;
}
}
- const int event_size = midi_event_size((unsigned char)status);
+ int event_size = midi_event_size((unsigned char)status);
if (event_size <= 0) {
- *size = 0;
- return 0;
+ if ((status & 0xff) == MIDI_CMD_COMMON_SYSEX) {
+ event_size = SMFReader::read_var_len(_fd) + 1;
+ } else {
+ *size = 0;
+ return 0;
+ }
}
// Make sure we have enough scratch buffer
if (event_size > 1)
fread((*buf) + 1, 1, *size - 1, _fd);
- /*printf("SMF %s read event: delta = %u, size = %u, data = ", _name.c_str(), *delta_t, *size);
+ /*printf("SMF read event: delta = %u, size = %u, data = ", *delta_t, *size);
for (size_t i=0; i < *size; ++i) {
printf("%X ", (*buf)[i]);
}
return (int)*size;
}
-template<typename T>
+template<typename Time>
void
-SMF<T>::append_event_unlocked(uint32_t delta_t, const Event<T>& ev)
+SMF<Time>::append_event_delta(uint32_t delta_t, const Event<Time>& ev)
{
if (ev.size() == 0)
return;
-
- const size_t stamp_size = write_var_len(delta_t);
- fwrite(ev.buffer(), 1, ev.size(), _fd);
+
+ size_t stamp_size = write_var_len(delta_t);
+ if (ev.buffer()[0] == MIDI_CMD_COMMON_SYSEX) {
+ fputc(MIDI_CMD_COMMON_SYSEX, _fd);
+ stamp_size += write_var_len(ev.size() - 1);
+ fwrite(ev.buffer() + 1, 1, ev.size() - 1, _fd);
+ } else {
+ fwrite(ev.buffer(), 1, ev.size(), _fd);
+ }
_track_size += stamp_size + ev.size();
_last_ev_time = ev.time();
_empty = false;
}
-template<typename T>
+template<typename Time>
void
-SMF<T>::begin_write(FrameTime start_frame)
+SMF<Time>::begin_write()
{
_last_ev_time = 0;
fseek(_fd, _header_size, SEEK_SET);
}
-template<typename T>
+template<typename Time>
void
-SMF<T>::end_write()
+SMF<Time>::end_write() throw(typename MIDIFile<Time>::FileError)
{
flush_header();
flush_footer();
}
-template<typename T>
+template<typename Time>
void
-SMF<T>::write_chunk_header(const char id[4], uint32_t length)
+SMF<Time>::write_chunk_header(const char id[4], uint32_t length)
{
const uint32_t length_be = GUINT32_TO_BE(length);
fwrite(&length_be, 4, 1, _fd);
}
-template<typename T>
+template<typename Time>
void
-SMF<T>::write_chunk(const char id[4], uint32_t length, void* data)
+SMF<Time>::write_chunk(const char id[4], uint32_t length, void* data)
{
write_chunk_header(id, length);
}
/** Returns the size (in bytes) of the value written. */
-template<typename T>
+template<typename Time>
size_t
-SMF<T>::write_var_len(uint32_t value)
+SMF<Time>::write_var_len(uint32_t value)
{
size_t ret = 0;