return 0;
}
+/** Attempt to open the SMF file for reading and writing.
+ *
+ * Currently SMFSource is always read/write.
+ *
+ * \return 0 on success
+ * -1 if the file can not be opened for reading,
+ * -2 if the file can not be opened for writing
+ */
int
SMFSource::open()
{
// We're making a new file
} else {
_fd = fopen(path().c_str(), "w+");
+ if (_fd == NULL) {
+ cerr << "ERROR: Can not open SMF file " << path() << " for writing: " <<
+ strerror(errno) << endl;
+ return -2;
+ }
_track_size = 4;
// Write a tentative header just to pad things out so writing happens in the right spot
flush_header();
- write_footer();
- seek_to_end();
+ flush_footer();
}
-
+
return (_fd == 0) ? -1 : 0;
}
void
-SMFSource::seek_to_end()
+SMFSource::close()
{
+ if (_fd) {
+ flush_header();
+ flush_footer();
+ fclose(_fd);
+ _fd = NULL;
+ }
+}
+
+void
+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);
+ //cerr << "SMFSource::seek_to_footer_position: At position: " << ftell(_fd);
+ size_t read_bytes = fread(buffer, sizeof(uint8_t), 4, _fd);
+ /*cerr << " read size: " << read_bytes << " buffer: ";
+ for (size_t i=0; i < read_bytes; ++i) {
+ printf("%x ", buffer[i]);
+ }
+ printf("\n");
+ */
+
+ 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
-SMFSource::flush_header ()
+SMFSource::flush_header()
{
// FIXME: write timeline position somehow?
- //cerr << "SMF Flushing header\n";
+ //cerr << path() << " SMF Flushing header\n";
assert(_fd);
int
SMFSource::flush_footer()
{
- fseek(_fd, 0, SEEK_END);
+ //cerr << path() << " SMF Flushing footer\n";
+ seek_to_footer_position();
write_footer();
+ seek_to_footer_position();
return 0;
}
void
SMFSource::write_footer()
{
- //cerr << "SMF " << name() << " writing EOT at byte " << ftell(_fd) << endl;
-
write_var_len(0);
char eot[3] = { 0xFF, 0x2F, 0x00 }; // end-of-track meta-event
fwrite(eot, 1, 3, _fd);
*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;
}
nframes_t
SMFSource::read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset, nframes_t negative_stamp_offset) const
{
- cerr << "SMF read_unlocked " << name() << " read " << start << ", count=" << cnt << ", offset=" << stamp_offset << endl;
+ //cerr << "SMF read_unlocked " << name() << " read " << start << ", count=" << cnt << ", offset=" << stamp_offset << endl;
// 64 bits ought to be enough for anybody
uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn
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)
void
SMFSource::append_event_unlocked(EventTimeUnit unit, const MIDI::Event& ev)
{
- //printf("%s - append chan = %u, time = %lf, size = %u, data = ", _path.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");
-
+
assert(ev.time() >= 0);
assert(ev.time() >= _last_ev_time);
{
MidiSource::mark_streaming_midi_write_started (mode, start_frame);
_last_ev_time = 0;
+ fseek(_fd, _header_size, SEEK_SET);
}
void
return;
}
+ _model->set_edited(false);
flush_header();
flush_footer();
-
-#if 0
- Glib::Mutex::Lock lm (_lock);
-
-
- next_peak_clear_should_notify = true;
-
- if (_peaks_built || pending_peak_builds.empty()) {
- _peaks_built = true;
- PeaksReady (); /* EMIT SIGNAL */
- }
-#endif
}
void
if (lock)
Glib::Mutex::Lock lm (_lock);
- if (_model && !force_reload && !_model->empty()) {
- //cerr << _name << " NOT reloading model " << _model.get() << " (" << _model->n_notes()
- // << " notes)" << endl;
+ if (_model && !force_reload && !_model->empty())
return;
- } else {
- cerr << _name << " loading model" << endl;
- }
if (! _model) {
_model = boost::shared_ptr<MidiModel>(new MidiModel(this));
_model->start_write();
- fseek(_fd, _header_size, 0);
+ fseek(_fd, _header_size, SEEK_SET);
uint64_t time = 0; /* in SMF ticks */
MIDI::Event ev;
}
_model->end_write(false);
+ _model->set_edited(false);
free(ev.buffer());
}