allegrosmfwr.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. // allegrosmfwr.cpp -- Allegro Standard Midi File Write
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <math.h>
  5. #include <errno.h>
  6. #include <string>
  7. #include <iostream>
  8. #include <fstream>
  9. using namespace std;
  10. #include "allegro.h"
  11. // event_queue is a list element that keeps track of pending
  12. // things to write to a track, including note-ons, note-offs,
  13. // updates, tempo changes, and time signatures
  14. //
  15. class event_queue{
  16. public:
  17. char type;//'n' for note, 'o' for off, 's' for time signature,
  18. // 'c' for tempo changes
  19. double time;
  20. long index; //of the event in mSeq->notes
  21. class event_queue *next;
  22. event_queue(char t, double when, long x, class event_queue *n) {
  23. type = t; time = when; index = x; next = n; }
  24. };
  25. class Alg_smf_write {
  26. public:
  27. Alg_smf_write(Alg_seq_ptr seq);
  28. ~Alg_smf_write();
  29. long channels_per_track; // used to encode track number into chan field
  30. // chan is actual_channel + channels_per_track * track_number
  31. // default is 100, set this to 0 to merge all tracks to 16 channels
  32. void write(ostream &file /* , midiFileFormat = 1 */);
  33. private:
  34. long previous_divs; // time in ticks of most recently written event
  35. void write_track(int i);
  36. void write_tempo(int divs, int tempo);
  37. void write_tempo_change(int i);
  38. void write_time_signature(int i);
  39. void write_note(Alg_note_ptr note, bool on);
  40. void write_update(Alg_update_ptr update);
  41. void write_text(Alg_update_ptr update, char type);
  42. void write_binary(int type_byte, const char *msg);
  43. void write_midi_channel_prefix(Alg_update_ptr update);
  44. void write_smpteoffset(Alg_update_ptr update, char *s);
  45. void write_data(int data);
  46. int to_midi_channel(int channel);
  47. int to_track(int channel);
  48. ostream *out_file;
  49. Alg_seq_ptr seq;
  50. int num_tracks; // number of tracks not counting tempo track
  51. int division; // divisions per quarter note, default = 120
  52. int initial_tempo;
  53. int timesig_num; // numerator of time signature
  54. int timesig_den; // denominator of time signature
  55. double timesig_when; // time of time signature
  56. int keysig; // number of sharps (+) or flats (-), -99 for undefined
  57. char keysig_mode; // 'M' or 'm' for major/minor
  58. double keysig_when; // time of key signature
  59. void write_delta(double event_time);
  60. void write_varinum(int num);
  61. void write_16bit(int num);
  62. void write_24bit(int num);
  63. void write_32bit(int num);
  64. };
  65. #define ROUND(x) (int) ((x)+0.5)
  66. Alg_smf_write::Alg_smf_write(Alg_seq_ptr a_seq)
  67. {
  68. out_file = nullptr;
  69. // at 100bpm (a nominal tempo value), we would like a division
  70. // to represent 1ms of time. So
  71. // d ticks/beat * 100 beats/min = 60,000 ms/min * 1 tick/ms
  72. // solving for d, d = 600
  73. division = 600; // divisions per quarter note
  74. timesig_num = timesig_den = 0; // initially undefined
  75. keysig = -99;
  76. keysig_mode = 0;
  77. initial_tempo = 500000;
  78. seq = a_seq;
  79. previous_divs = 0; // used to compute deltas for midifile
  80. }
  81. Alg_smf_write::~Alg_smf_write()
  82. {
  83. }
  84. // sorting is quite subtle due to rounding
  85. // For example, suppose times from a MIDI file are exact, but in
  86. // decimal round to TW0.4167 Q0.3333. Since the time in whole notes
  87. // rounded up, this note will start late. Even though the duration
  88. // rounded down, the amount is 1/4 as much because units are quarter
  89. // notes. Therefore, the total roundup is 0.0001 beats. This is
  90. // enough to cause the note to sort later in the queue, perhaps
  91. // coming after a new note-on on the same pitch, and resulting in
  92. // a turning on-off, on-off into on, on, off, off if data is moved
  93. // to Allegro (ascii) format with rounding and then back to SMF.
  94. //
  95. // The solution here is to consider things that round to the same
  96. // tick to be simultaneous. Then, be sure to deal with note-offs
  97. // before note-ons. We're going to do that by using event_queue
  98. // times that are rounded to the nearest tick time. Except note-offs
  99. // are going to go in with times that are 1/4 tick earlier so they
  100. // get scheduled first, but still end up on the same tick.
  101. //
  102. event_queue* push(event_queue *queue, event_queue *event)
  103. {
  104. // printf("push: %.6g, %c, %d\n", event->time, event->type, event->index);
  105. if (queue == nullptr) {
  106. event->next = nullptr;
  107. return event;
  108. }
  109. event_queue *marker1 = nullptr;
  110. event_queue *marker2 = queue;
  111. while (marker2 != nullptr && marker2->time <= event->time) {
  112. marker1 = marker2;
  113. marker2 = marker2->next;
  114. }
  115. event->next = marker2;
  116. if (marker1 != nullptr) {
  117. marker1->next=event;
  118. return queue;
  119. } else return event;
  120. }
  121. void print_queue(event_queue *q)
  122. {
  123. printf("Printing queue. . .\n");
  124. event_queue *q2=q;
  125. while (q2) {
  126. printf("%c at %f ;", q2->type, q2->time);
  127. q2 = q2->next;
  128. }
  129. printf("\nDone printing.\n");
  130. }
  131. void Alg_smf_write::write_note(Alg_note_ptr note, bool on)
  132. {
  133. double event_time = (on ? note->time : note->time + note->dur);
  134. write_delta(event_time);
  135. //printf("deltaDivisions: %d, beats elapsed: %g, on? %c\n", deltaDivisions, note->time, on);
  136. char chan = char(note->chan & 15);
  137. int pitch = int(note->pitch + 0.5);
  138. if (pitch < 0) {
  139. pitch = pitch % 12;
  140. } else if (pitch > 127) {
  141. pitch = (pitch % 12) + 120; // put pitch in 10th octave
  142. if (pitch > 127) pitch -= 12; // or 9th octave
  143. }
  144. out_file->put(0x90 + chan);
  145. out_file->put(pitch);
  146. if (on) {
  147. int vel = (int) note->loud;
  148. if (vel <= 0) vel = 1;
  149. write_data(vel);
  150. } else out_file->put(0); // note-off indicated by velocty zero
  151. }
  152. void Alg_smf_write::write_midi_channel_prefix(Alg_update_ptr update)
  153. {
  154. if (update->chan >= 0) { // write MIDI Channel Prefix
  155. write_delta(update->time);
  156. out_file->put('\xFF'); // Meta Event
  157. out_file->put('\x20'); // Type code for MIDI Channel Prefix
  158. out_file->put(1); // length
  159. out_file->put(to_midi_channel(update->chan));
  160. // one thing odd about the Std MIDI File spec is that once
  161. // you turn on MIDI Channel Prefix, there seems to be no
  162. // way to cancel it unless a non-Meta event shows up. We
  163. // don't do any analysis to avoid assigning channels to
  164. // meta events.
  165. }
  166. }
  167. void Alg_smf_write::write_text(Alg_update_ptr update, char type)
  168. {
  169. write_midi_channel_prefix(update);
  170. write_delta(update->time);
  171. out_file->put('\xFF');
  172. out_file->put(type);
  173. out_file->put((char) strlen(update->parameter.s));
  174. *out_file << update->parameter.s;
  175. }
  176. void Alg_smf_write::write_smpteoffset(Alg_update_ptr update, char *s)
  177. {
  178. write_midi_channel_prefix(update);
  179. write_delta(update->time);
  180. out_file->put('\xFF'); // meta event
  181. out_file->put('\x54'); // smpte offset type code
  182. out_file->put(5); // length
  183. for (int i = 0; i < 5; i++) *out_file << s[i];
  184. }
  185. // write_data - limit data to the range of [0...127] and write it
  186. void Alg_smf_write::write_data(int data)
  187. {
  188. if (data < 0) data = 0;
  189. else if (data > 0x7F) data = 0x7F;
  190. out_file->put(data);
  191. }
  192. int Alg_smf_write::to_midi_channel(int channel)
  193. {
  194. // allegro track number is stored as multiple of 100
  195. // also mask off all but 4 channel bits just in case
  196. if (channels_per_track > 0) channel %= channels_per_track;
  197. return channel & 0xF;
  198. }
  199. int Alg_smf_write::to_track(int channel)
  200. {
  201. if (channel == -1) return 0;
  202. return channel / channels_per_track;
  203. }
  204. static char hex_to_nibble(char c)
  205. {
  206. if (isalpha(c)) {
  207. return 10 + (toupper(c) - 'A');
  208. } else {
  209. return c - '0';
  210. }
  211. }
  212. static char hex_to_char(const char *s)
  213. {
  214. return (hex_to_nibble(s[0]) << 4) + hex_to_nibble(s[1]);
  215. }
  216. void Alg_smf_write::write_binary(int type_byte, const char *msg)
  217. {
  218. int len = strlen(msg) / 2;
  219. out_file->put(type_byte);
  220. write_varinum(len);
  221. for (int i = 0; i < len; i++) {
  222. out_file->put(hex_to_char(msg));
  223. msg += 2;
  224. }
  225. }
  226. void Alg_smf_write::write_update(Alg_update_ptr update)
  227. {
  228. const char *name = update->parameter.attr_name();
  229. /****Non-Meta Events****/
  230. if (!strcmp(name, "pressurer")) {
  231. write_delta(update->time);
  232. if (update->get_identifier() < 0) { // channel pressure message
  233. out_file->put(0xD0 + to_midi_channel(update->chan));
  234. write_data((int)(update->parameter.r * 127));
  235. } else { // just 1 key -- poly pressure
  236. out_file->put(0xA0 + to_midi_channel(update->chan));
  237. write_data(update->get_identifier());
  238. write_data((int)(update->parameter.r * 127));
  239. }
  240. } else if (!strcmp(name, "programi")) {
  241. write_delta(update->time);
  242. out_file->put(0xC0 + to_midi_channel(update->chan));
  243. write_data(update->parameter.i);
  244. } else if (!strcmp(name, "bendr")) {
  245. int temp = ROUND(0x2000 * (update->parameter.r + 1));
  246. if (temp > 0x3fff) temp = 0x3fff; // 14 bits maximum
  247. if (temp < 0) temp = 0;
  248. int c1 = temp & 0x7F; // low 7 bits
  249. int c2 = temp >> 7; // high 7 bits
  250. write_delta(update->time);
  251. out_file->put(0xE0 + to_midi_channel(update->chan));
  252. write_data(c1);
  253. write_data(c2);
  254. } else if (!strncmp(name, "control", 7) &&
  255. update->parameter.attr_type() == 'r') {
  256. int ctrlnum = atoi(name + 7);
  257. int val = ROUND(update->parameter.r * 127);
  258. write_delta(update->time);
  259. out_file->put(0xB0 + to_midi_channel(update->chan));
  260. write_data(ctrlnum);
  261. write_data(val);
  262. } else if (!strcmp(name, "sysexs") &&
  263. update->parameter.attr_type() == 's') {
  264. const char *s = update->parameter.s;
  265. if (s[0] && s[1] && toupper(s[0]) == 'F' && s[1] == '0') {
  266. s += 2; // skip the initial "F0" byte in message: it is implied
  267. }
  268. write_delta(update->time);
  269. write_binary(0xF0, s);
  270. } else if (!strcmp(name, "sqspecifics") &&
  271. update->parameter.attr_type() == 's') {
  272. const char *s = update->parameter.s;
  273. write_delta(update->time);
  274. out_file->put('\xFF');
  275. write_binary(0x7F, s);
  276. /****Text Events****/
  277. } else if (!strcmp(name, "texts")) {
  278. write_text(update, 0x01);
  279. } else if (!strcmp(name, "copyrights")) {
  280. write_text(update, 0x02);
  281. } else if (!strcmp(name, "seqnames") || !strcmp(name, "tracknames")) {
  282. write_text(update, 0x03);
  283. } else if (!strcmp(name, "instruments")) {
  284. write_text(update, 0x04);
  285. } else if (!strcmp(name, "lyrics")) {
  286. write_text(update, 0x05);
  287. } else if (!strcmp(name, "markers")) {
  288. write_text(update, 0x06);
  289. } else if (!strcmp(name, "cues")) {
  290. write_text(update, 0x07);
  291. } else if (!strcmp(name, "miscs")) {
  292. write_text(update, 0x08);
  293. /****Other Events****/
  294. } else if (!strcmp(name, "smpteoffsets")) {
  295. #define decimal(p) (((p)[0] - '0') * 10 + ((p)[1] - '0'))
  296. // smpteoffset is specified as "24fps:00h:10m:00s:11.00f"
  297. // the following simple parser does not reject all badly
  298. // formatted strings, but it should parse good strings ok
  299. const char *s = update->parameter.s;
  300. int len = strlen(s);
  301. char smpteoffset[5];
  302. if (len < 24) return; // not long enough, must be bad format
  303. int fps = 0;
  304. if (s[0] == '2') {
  305. if (s[1] == '4') fps = 0;
  306. else if (s[1] == '5') fps = 1;
  307. else if (s[1] == '9') {
  308. fps = 2;
  309. if (len != 27) return; // not right length
  310. s += 3; // cancel effect of longer string
  311. }
  312. } else fps = 3;
  313. s += 6; int hours = decimal(s);
  314. s += 4; int mins = decimal(s);
  315. s += 4; int secs = decimal(s);
  316. s += 4; int frames = decimal(s);
  317. s += 3; int subframes = decimal(s);
  318. smpteoffset[0] = (fps << 6) + hours;
  319. smpteoffset[1] = mins;
  320. smpteoffset[2] = secs;
  321. smpteoffset[3] = frames;
  322. smpteoffset[4] = subframes;
  323. write_smpteoffset(update, smpteoffset);
  324. // key signature is special because it takes two events in the Alg_seq
  325. // structure to make one midi file event. When we encounter one or
  326. // the other event, we'll just record it in the Alg_smf_write object.
  327. // After both events are seen, we write the data. (See below.)
  328. } else if (!strcmp(name, "keysigi")) {
  329. keysig = update->parameter.i;
  330. keysig_when = update->time;
  331. } else if (!strcmp(name, "modea")) {
  332. if (!strcmp(alg_attr_name(update->parameter.a), "major"))
  333. keysig_mode = 'M';
  334. else keysig_mode = 'm';
  335. keysig_when = update->time;
  336. }
  337. if (keysig != -99 && keysig_mode) { // write when both are defined
  338. write_delta(keysig_when);
  339. out_file->put('\xFF');
  340. out_file->put('\x59');
  341. out_file->put(2);
  342. // mask off high bits so that this value appears to be positive
  343. // i.e. -1 -> 0xFF (otherwise, write_data will clip -1 to 0)
  344. out_file->put(keysig & 0xFF);
  345. out_file->put(keysig_mode == 'm');
  346. keysig = -99;
  347. keysig_mode = false;
  348. }
  349. //printf("Update: %s, key: %g\n", update->parameter.attr_name(), update->key);
  350. }
  351. // see notes on event_queue::push, TICK_TIME converts from beat to
  352. // the number of the nearest tick. The second parameter is an offset in
  353. // quarter ticks. By scheduling with -1, note-offs should get dispatched
  354. // first. Note that TICK_TIME only determines the order of events, so
  355. // it is ok to change units from beats to ticks, saving a divide.
  356. #define TICK_TIME(t, o) (ROUND((t) * division) + 0.25 * (o))
  357. void Alg_smf_write::write_track(int i)
  358. {
  359. int j = 0; // note index
  360. Alg_events &notes = seq->track_list[i];
  361. event_queue *pending = nullptr;
  362. if (notes.length() > 0) {
  363. pending = new event_queue('n', TICK_TIME(notes[j]->time, 0), 0, nullptr);
  364. }
  365. if (i == 0) { // track 0 may have tempo and timesig info
  366. if (seq->get_time_map()->last_tempo_flag || seq->get_time_map()->beats.len > 0) {
  367. pending = push(pending, new event_queue('c', 0.0, 0, nullptr));
  368. }
  369. if (seq->time_sig.length() > 0) {
  370. pending = push(pending, new event_queue('s',
  371. TICK_TIME(seq->time_sig[0].beat, 0), 0, nullptr));
  372. }
  373. }
  374. while (pending) {
  375. event_queue *current = pending;
  376. pending = pending->next;
  377. if (current->type == 'n') {
  378. Alg_note_ptr n = (Alg_note_ptr) notes[current->index];
  379. if (n->is_note()) {
  380. write_note(n, true);
  381. pending = push(pending, new event_queue('o',
  382. TICK_TIME(n->time + n->dur, -1), current->index, nullptr));
  383. } else if (n->is_update()) {
  384. Alg_update_ptr u = (Alg_update_ptr) n;
  385. write_update(u);
  386. }
  387. int next = current->index + 1;
  388. if (next < notes.length()) {
  389. current->time = TICK_TIME(notes[next]->time, 0);
  390. current->index = next;
  391. pending = push(pending, current);
  392. }
  393. } else if (current->type == 'o') { //note-off
  394. Alg_note_ptr n = (Alg_note_ptr) notes[current->index];
  395. write_note(n, false);
  396. delete current;
  397. } else if (current->type == 'c') { // tempo change
  398. write_tempo_change(current->index);
  399. current->index++; // -R
  400. if (current->index < seq->get_time_map()->beats.len) {
  401. current->time =
  402. TICK_TIME(seq->get_time_map()->
  403. beats[current->index].beat, 0);
  404. pending = push(pending, current);
  405. } else {
  406. delete current;
  407. }
  408. } else if (current->type == 's') { // time sig
  409. write_time_signature(current->index);
  410. current->index++;
  411. if (current->index < seq->time_sig.length()) {
  412. current->time =
  413. TICK_TIME(seq->time_sig[current->index].beat, 0);
  414. pending = push(pending, current);
  415. } else {
  416. delete current;
  417. }
  418. }
  419. }
  420. }
  421. void Alg_smf_write::write_tempo(int divs, int tempo)
  422. {
  423. // printf("Inserting tempo %f after %f clocks.\n", tempo, delta);
  424. write_varinum(divs - previous_divs);
  425. previous_divs = divs;
  426. out_file->put('\xFF');
  427. out_file->put('\x51');
  428. out_file->put('\x03');
  429. write_24bit((int)tempo);
  430. }
  431. void Alg_smf_write::write_tempo_change(int i)
  432. // i is index of tempo map
  433. {
  434. // extract tempo map
  435. Alg_beats &b = seq->get_time_map()->beats;
  436. double tempo;
  437. long divs;
  438. if (i < seq->get_time_map()->beats.len - 1) {
  439. tempo = 1000000 * ((b[i+1].time - b[i].time) /
  440. (b[i+1].beat - b[i].beat));
  441. divs = ROUND(b[i].beat * division);
  442. write_tempo(divs, ROUND(tempo));
  443. } else if (seq->get_time_map()->last_tempo_flag) { // write the final tempo
  444. divs = ROUND(division * b[i].beat);
  445. tempo = (1000000.0 / seq->get_time_map()->last_tempo);
  446. write_tempo(divs, ROUND(tempo));
  447. }
  448. }
  449. void Alg_smf_write::write_time_signature(int i)
  450. {
  451. Alg_time_sigs &ts = seq->time_sig;
  452. write_delta(ts[i].beat);
  453. // write the time signature
  454. out_file->put('\xFF');
  455. out_file->put('\x58'); // time signature
  456. out_file->put('\x04'); // length of message
  457. out_file->put(ROUND(ts[i].num));
  458. int den = ROUND(ts[i].den);
  459. int den_byte = 0;
  460. while (den > 1) { // compute the log2 of denominator
  461. den_byte++;
  462. den >>= 1;
  463. }
  464. out_file->put(den_byte);
  465. out_file->put(24); // clocks per quarter
  466. out_file->put(8); // 32nd notes per 24 clocks
  467. }
  468. void Alg_smf_write::write(ostream &file)
  469. {
  470. int track_len_offset;
  471. int track_end_offset;
  472. int track_len;
  473. out_file = &file;
  474. // Header
  475. file << "MThd";
  476. write_32bit(6); // chunk length
  477. write_16bit(1); // format 1 MIDI file
  478. write_16bit(seq->tracks()); // number of tracks
  479. write_16bit(division); // divisions per quarter note
  480. // write_ all tracks
  481. seq->convert_to_beats();
  482. int i;
  483. for (i = 0; i < seq->tracks(); i++) {
  484. previous_divs = 0;
  485. *out_file << "MTrk";
  486. track_len_offset = out_file->tellp();
  487. write_32bit(0); // track len placeholder
  488. write_track(i);
  489. // End of track event
  490. write_varinum(0); // delta time
  491. out_file->put('\xFF');
  492. out_file->put('\x2F');
  493. out_file->put('\x00');
  494. // Go back and write in the length of the track
  495. track_end_offset = out_file->tellp();
  496. track_len = track_end_offset - track_len_offset - 4;
  497. out_file->seekp(track_len_offset);
  498. write_32bit(track_len);
  499. out_file->seekp(track_end_offset);
  500. }
  501. }
  502. void Alg_smf_write::write_16bit(int num)
  503. {
  504. out_file->put((num & 0xFF00) >> 8);
  505. out_file->put(num & 0xFF);
  506. }
  507. void Alg_smf_write::write_24bit(int num)
  508. {
  509. out_file->put((num & 0xFF0000) >> 16);
  510. out_file->put((num & 0xFF00) >> 8);
  511. out_file->put((num & 0xFF));
  512. }
  513. void Alg_smf_write::write_32bit(int num)
  514. {
  515. out_file->put((num & 0xFF000000) >> 24);
  516. out_file->put((num & 0xFF0000) >> 16);
  517. out_file->put((num & 0xFF00) >> 8);
  518. out_file->put((num & 0xFF));
  519. }
  520. void Alg_smf_write::write_delta(double event_time)
  521. {
  522. // divisions is ideal absolute time in divisions
  523. long divisions = ROUND(division * event_time);
  524. long delta_divs = divisions - previous_divs;
  525. write_varinum(delta_divs);
  526. previous_divs = divisions;
  527. }
  528. void Alg_smf_write::write_varinum(int value)
  529. {
  530. if(value<0) value=0;//this line should not have to be here!
  531. int buffer;
  532. buffer = value & 0x7f;
  533. while ((value >>= 7) > 0) {
  534. buffer <<= 8;
  535. buffer |= 0x80;
  536. buffer += (value & 0x7f);
  537. }
  538. for(;;) {
  539. out_file->put(buffer);
  540. if (buffer & 0x80)
  541. buffer >>= 8;
  542. else
  543. break;
  544. }
  545. }
  546. void Alg_seq::smf_write(ostream &file)
  547. {
  548. Alg_smf_write writer(this);
  549. writer.write(file);
  550. }
  551. bool Alg_seq::smf_write(const char *filename)
  552. {
  553. ofstream outf(filename, ios::binary | ios::out);
  554. if (outf.fail()) return false;
  555. smf_write(outf);
  556. outf.close();
  557. return true;
  558. }