23 #include <glibmm/miscutils.h>
33 SMFReader::SMFReader(
const string& filename)
39 if (filename.length() > 0) {
56 throw logic_error(
"Attempt to start new read while write in progress.");
58 cout <<
"Opening SMF file " << filename <<
" for reading." << endl;
60 _fd = fopen(filename.c_str(),
"r+");
64 fseek(_fd, 0, SEEK_SET);
67 fread(mthd, 1, 4, _fd);
68 if (strcmp(mthd,
"MThd")) {
69 cerr << filename <<
" is not an SMF file, aborting." << endl;
76 fseek(_fd, 8, SEEK_SET);
78 fread(&type_be, 2, 1, _fd);
79 _type = GUINT16_FROM_BE(type_be);
82 uint16_t num_tracks_be = 0;
83 fread(&num_tracks_be, 2, 1, _fd);
84 _num_tracks = GUINT16_FROM_BE(num_tracks_be);
88 fread(&ppqn_be, 2, 1, _fd);
89 _ppqn = GUINT16_FROM_BE(ppqn_be);
92 if ((_ppqn & 0x8000) != 0)
111 throw logic_error(
"Seek to track 0 out of range (must be >= 1)");
114 throw logic_error(
"Attempt to seek to track on unopened SMF file.");
116 unsigned track_pos = 0;
118 fseek(_fd, 14, SEEK_SET);
121 uint32_t chunk_size = 0;
124 fread(
id, 1, 4, _fd);
126 if (!strcmp(
id,
"MTrk")) {
129 std::cerr <<
"Unknown chunk ID " <<
id << endl;
132 uint32_t chunk_size_be;
133 fread(&chunk_size_be, 4, 1, _fd);
134 chunk_size = GUINT32_FROM_BE(chunk_size_be);
136 if (track_pos == track)
139 fseek(_fd, chunk_size, SEEK_CUR);
142 if (!feof(_fd) && track_pos == track) {
144 _track_size = chunk_size;
169 uint32_t* delta_time)
173 throw logic_error(
"Attempt to read from unopened SMF file");
175 if (!_fd || feof(_fd)) {
185 static uint8_t last_status = 0;
186 static uint32_t last_size = 0;
188 *delta_time = read_var_len(_fd);
189 int status = fgetc(_fd);
192 else if (status > 0xFF)
196 if (last_status == 0)
198 status = last_status;
199 *ev_size = last_size;
200 fseek(_fd, -1, SEEK_CUR);
202 last_status = status;
204 last_size = *ev_size;
207 buf[0] = (uint8_t)status;
209 if (status == 0xFF) {
213 uint8_t type = fgetc(_fd);
214 const uint32_t size = read_var_len(_fd);
220 if ((uint8_t)type == 0x2F) {
223 fseek(_fd, size, SEEK_CUR);
228 if (*ev_size > buf_len || *ev_size == 0 || feof(_fd)) {
231 fseek(_fd, *ev_size - 1, SEEK_CUR);
238 fread(buf+1, 1, *ev_size - 1, _fd);
240 if ((buf[0] & 0xF0) == 0x90 && buf[2] == 0) {
241 buf[0] = (0x80 | (buf[0] & 0x0F));
269 if ( (value = getc(fd)) & 0x80 ) {
274 value = (value << 7) + ((c = getc(fd)) & 0x7F);
int read_event(size_t buf_len, uint8_t *buf, uint32_t *ev_size, uint32_t *ev_delta_time)
static int midi_event_size(uint8_t status)
bool seek_to_track(unsigned track)
static uint32_t read_var_len(FILE *fd)
bool open(const std::string &filename)