PageRenderTime 57ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/frontends/CsoundAC/allegro.cpp

https://github.com/tim81cortes/csound
C++ | 3516 lines | 2491 code | 387 blank | 638 comment | 558 complexity | f781d11ec5458eac6955eee0a82cddf9 MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, BSD-3-Clause, LGPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. // Allegro: music representation system, with
  2. // extensible in-memory sequence structure
  3. // upward compatible with MIDI
  4. // implementations in C++ and Serpent
  5. // external, text-based representation
  6. // compatible with Aura
  7. //
  8. /* CHANGE LOG:
  9. 04 apr 03 -- fixed bug in add_track that caused infinite loop
  10. */
  11. #include "assert.h"
  12. #include "stdlib.h"
  13. #include "stdio.h"
  14. #include "string.h"
  15. #include "memory.h"
  16. #include <iostream>
  17. #include <fstream>
  18. using namespace std;
  19. #include "allegro.h"
  20. #include "algrd_internal.h"
  21. #include "algsmfrd_internal.h"
  22. // #include "trace.h" -- only needed for debugging
  23. #include "math.h"
  24. #define STREQL(x, y) (strcmp(x, y) == 0)
  25. #define MAX(x, y) ((x) > (y) ? (x) : (y))
  26. #define ROUND(x) ((int) ((x) + 0.5))
  27. // 4311 is type cast ponter to long warning
  28. // 4996 is warning against strcpy
  29. // 4267 is size_t to long warning
  30. #pragma warning(disable: 4311 4996 4267)
  31. Alg_atoms symbol_table;
  32. Serial_read_buffer Alg_track::ser_read_buf; // declare the static variables
  33. Serial_write_buffer Alg_track::ser_write_buf;
  34. bool within(double d1, double d2, double epsilon)
  35. {
  36. d1 -= d2;
  37. return d1 < epsilon && d1 > -epsilon;
  38. }
  39. char *heapify(const char *s)
  40. {
  41. char *h = new char[strlen(s) + 1];
  42. strcpy(h, s);
  43. return h;
  44. }
  45. void Alg_atoms::expand()
  46. {
  47. maxlen = (maxlen + 5); // extra growth for small sizes
  48. maxlen += (maxlen >> 2); // add 25%
  49. Alg_attribute *new_atoms = new Alg_attribute[maxlen];
  50. // now do copy
  51. memcpy(new_atoms, atoms, len * sizeof(Alg_attribute));
  52. if (atoms) delete[] atoms;
  53. atoms = new_atoms;
  54. }
  55. // insert_new -- insert an attribute name and type
  56. //
  57. // attributes are stored as a string consisting of the type
  58. // (a char) followed by the attribute name. This makes it
  59. // easy to retrieve the type or the name or both.
  60. //
  61. Alg_attribute Alg_atoms::insert_new(const char *name, char attr_type)
  62. {
  63. if (len == maxlen) expand();
  64. char *h = new char[strlen(name) + 2];
  65. strcpy(h + 1, name);
  66. *h = attr_type;
  67. atoms[len++] = h;
  68. return h;
  69. }
  70. Alg_attribute Alg_atoms::insert_attribute(Alg_attribute attr)
  71. {
  72. // should use hash algorithm
  73. for (int i = 0; i < len; i++) {
  74. if (STREQL(attr, atoms[i])) {
  75. return atoms[i];
  76. }
  77. }
  78. return insert_new(attr + 1, attr[0]);
  79. }
  80. Alg_attribute Alg_atoms::insert_string(const char *name)
  81. {
  82. char attr_type = name[strlen(name) - 1];
  83. for (int i = 0; i < len; i++) {
  84. if (attr_type == atoms[i][0] &&
  85. STREQL(name, atoms[i] + 1)) {
  86. return atoms[i];
  87. }
  88. }
  89. return insert_new(name, attr_type);
  90. }
  91. void Alg_parameter::copy(Alg_parameter_ptr parm)
  92. {
  93. *this = *parm; // copy all fields
  94. // if the value is a string, copy the string
  95. if (attr_type() == 's') {
  96. s = heapify(s);
  97. }
  98. }
  99. void Alg_parameter::show()
  100. {
  101. switch (attr[0]) {
  102. case 'r':
  103. printf("%s:%g", attr_name(), r);
  104. break;
  105. case 's':
  106. printf("%s:%s", attr_name(), s);
  107. break;
  108. case 'i':
  109. printf("%s:%ld", attr_name(), i);
  110. break;
  111. case 'l':
  112. printf("%s:%s", attr_name(), (l ? "t" : "f"));
  113. break;
  114. case 'a':
  115. printf("%s:%s", attr_name(), a);
  116. break;
  117. }
  118. }
  119. Alg_parameter::~Alg_parameter()
  120. {
  121. if (attr_type() == 's' && s) {
  122. delete[] s;
  123. }
  124. }
  125. void Alg_parameters::insert_real(Alg_parameters **list, const char *name,
  126. double r)
  127. {
  128. Alg_parameters_ptr a = new Alg_parameters(*list);
  129. *list = a;
  130. a->parm.set_attr(symbol_table.insert_string(name));
  131. a->parm.r = r;
  132. assert(a->parm.attr_type() == 'r');
  133. }
  134. void Alg_parameters::insert_string(Alg_parameters **list, const char *name,
  135. const char *s)
  136. {
  137. Alg_parameters_ptr a = new Alg_parameters(*list);
  138. *list = a;
  139. a->parm.set_attr(symbol_table.insert_string(name));
  140. // string is deleted when parameter is deleted
  141. a->parm.s = heapify(s);
  142. assert(a->parm.attr_type() == 's');
  143. }
  144. void Alg_parameters::insert_integer(Alg_parameters **list, const char *name,
  145. long i)
  146. {
  147. Alg_parameters_ptr a = new Alg_parameters(*list);
  148. *list = a;
  149. a->parm.set_attr(symbol_table.insert_string(name));
  150. a->parm.i = i;
  151. assert(a->parm.attr_type() == 'i');
  152. }
  153. void Alg_parameters::insert_logical(Alg_parameters **list, const char *name,
  154. bool l)
  155. {
  156. Alg_parameters_ptr a = new Alg_parameters(*list);
  157. *list = a;
  158. a->parm.set_attr(symbol_table.insert_string(name));
  159. a->parm.l = l;
  160. assert(a->parm.attr_type() == 'l');
  161. }
  162. void Alg_parameters::insert_atom(Alg_parameters **list, const char *name,
  163. const char *s)
  164. {
  165. Alg_parameters_ptr a = new Alg_parameters(*list);
  166. *list = a;
  167. a->parm.set_attr(symbol_table.insert_string(name));
  168. a->parm.a = symbol_table.insert_string(s);
  169. assert(a->parm.attr_type() == 'a');
  170. }
  171. Alg_parameters *Alg_parameters::remove_key(Alg_parameters **list,
  172. const char *name)
  173. {
  174. while (*list) {
  175. if (STREQL((*list)->parm.attr_name(), name)) {
  176. Alg_parameters_ptr p = *list;
  177. *list = p->next;
  178. p->next = NULL;
  179. return p; // caller should free this pointer
  180. }
  181. list = &((*list)->next);
  182. }
  183. return NULL;
  184. }
  185. Alg_parameter_ptr Alg_parameters::find(Alg_attribute attr)
  186. {
  187. assert(attr);
  188. Alg_parameters_ptr temp = this;
  189. while (temp) {
  190. if (temp->parm.attr == attr) {
  191. return &(temp->parm);
  192. }
  193. }
  194. return NULL;
  195. }
  196. int Alg_event::get_type_code()
  197. {
  198. if (!is_note()) {
  199. const char* attr = get_attribute();
  200. if (STREQL(attr, "gater")) // volume change
  201. return ALG_GATE;
  202. if (STREQL(attr, "bendr")) // pitch bend
  203. return ALG_BEND;
  204. if (strncmp(attr, "control", 7) == 0) // control change
  205. // note that midi control changes have attributes of the form
  206. // "control<n>" where n is the decimal number (as a character string)
  207. // of the midi controller, e.g. control2 is the breath controller.
  208. // We don't check for decimal numbers in the range 0-127, so any
  209. // attribute that begins with "control" is an ALG_CONTROL:
  210. return ALG_CONTROL;
  211. if (STREQL(attr, "programi")) // program change
  212. return ALG_PROGRAM;
  213. if (STREQL(attr, "pressurer")) // pressure change
  214. return ALG_PRESSURE;
  215. if (STREQL(attr, "keysigi")) // key signature
  216. return ALG_KEYSIG;
  217. if (STREQL(attr, "timesig_numi")) // time signature numerator
  218. return ALG_TIMESIG_NUM;
  219. if (STREQL(attr, "timesig_deni")) // time signature denominator
  220. return ALG_TIMESIG_DEN;
  221. return ALG_OTHER;
  222. }
  223. return ALG_NOTE; // it is a note
  224. }
  225. void Alg_event::set_parameter(Alg_parameter_ptr new_parameter)
  226. {
  227. Alg_parameter_ptr parm;
  228. if (is_note()) {
  229. Alg_note_ptr note = (Alg_note_ptr) this;
  230. parm = note->parameters->find(new_parameter->attr);
  231. if (!parm) {
  232. note->parameters = new Alg_parameters(note->parameters);
  233. parm = &(note->parameters->parm);
  234. }
  235. } else { // update
  236. Alg_update_ptr update = (Alg_update_ptr) this;
  237. parm = &(update->parameter);
  238. }
  239. parm->copy(new_parameter); // copy entire parameter
  240. }
  241. void Alg_event::set_string_value(const char *a, const char *value)
  242. {
  243. assert(a); // must be non-null
  244. Alg_attribute attr = symbol_table.insert_string(a);
  245. assert(attr[0] == 's');
  246. Alg_parameter parm;
  247. parm.set_attr(attr);
  248. parm.s = value;
  249. set_parameter(&parm);
  250. parm.s = NULL; // do this to prevent string from being freed
  251. }
  252. void Alg_event::set_real_value(const char *a, double value)
  253. {
  254. assert(a); // must be non-null
  255. // attr is like a, but it has the type code prefixed for
  256. // fast lookup, and it is a unique string in symbol_table
  257. // e.g. a="attackr" -> attr="rattackr"
  258. Alg_attribute attr = symbol_table.insert_string(a);
  259. assert(attr[0] == 'r');
  260. Alg_parameter parm;
  261. parm.set_attr(attr);
  262. parm.r = value;
  263. set_parameter(&parm);
  264. // since type is 'r' we don't have to NULL the string
  265. }
  266. void Alg_event::set_logical_value(const char *a, bool value)
  267. {
  268. assert(a); // must be non-null
  269. Alg_attribute attr = symbol_table.insert_string(a);
  270. assert(attr[0] == 'l');
  271. Alg_parameter parm;
  272. parm.set_attr(attr);
  273. parm.l = value;
  274. set_parameter(&parm);
  275. // since type is 'l' we don't have to NULL the string
  276. }
  277. void Alg_event::set_integer_value(const char *a, long value)
  278. {
  279. assert(a); // must be non-null
  280. Alg_attribute attr = symbol_table.insert_string(a);
  281. assert(attr[0] == 'i');
  282. Alg_parameter parm;
  283. parm.set_attr(attr);
  284. parm.i = value;
  285. set_parameter(&parm);
  286. // since tpye is 'i' we don't have to NULL the string
  287. }
  288. void Alg_event::set_atom_value(const char *a, const char *value)
  289. {
  290. assert(a); // must be non-null
  291. Alg_attribute attr = symbol_table.insert_string(a);
  292. assert(attr[0] == 'a');
  293. Alg_parameter parm;
  294. parm.set_attr(attr);
  295. parm.a = value;
  296. set_parameter(&parm);
  297. /* since type is 'a' we don't have to null the string */
  298. }
  299. float Alg_event::get_pitch()
  300. {
  301. assert(is_note());
  302. Alg_note* note = (Alg_note *) this;
  303. return note->pitch;
  304. }
  305. float Alg_event::get_loud()
  306. {
  307. assert(is_note());
  308. Alg_note* note = (Alg_note *) this;
  309. return note->loud;
  310. }
  311. double Alg_event::get_start_time()
  312. {
  313. assert(is_note());
  314. Alg_note* note = (Alg_note *) this;
  315. return note->time;
  316. }
  317. double Alg_event::get_end_time()
  318. {
  319. assert(is_note());
  320. Alg_note* note = (Alg_note *) this;
  321. return note->time + note->dur;
  322. }
  323. double Alg_event::get_duration()
  324. {
  325. assert(is_note());
  326. Alg_note* note = (Alg_note *) this;
  327. return note->dur;
  328. }
  329. void Alg_event::set_pitch(float p)
  330. {
  331. assert(is_note());
  332. Alg_note* note = (Alg_note *) this;
  333. note->pitch = p;
  334. }
  335. void Alg_event::set_loud(float l)
  336. {
  337. assert(is_note());
  338. Alg_note *note = (Alg_note *) this;
  339. note->loud = l;
  340. }
  341. void Alg_event::set_duration(double d)
  342. {
  343. assert(is_note());
  344. Alg_note* note = (Alg_note *) this;
  345. note->dur = d;
  346. }
  347. bool Alg_event::has_attribute(const char *a)
  348. {
  349. assert(is_note());
  350. assert(a); // must be non-null
  351. Alg_note* note = (Alg_note *) this;
  352. Alg_attribute attr = symbol_table.insert_string(a);
  353. Alg_parameter_ptr parm = note->parameters->find(attr);
  354. return parm != NULL;
  355. }
  356. char Alg_event::get_attribute_type(const char *a)
  357. {
  358. assert(is_note());
  359. assert(a);
  360. return a[strlen(a) - 1];
  361. }
  362. const char *Alg_event::get_string_value(const char *a, const char *value)
  363. {
  364. assert(is_note());
  365. assert(a); // must be non-null
  366. Alg_note* note = (Alg_note *) this;
  367. Alg_attribute attr = symbol_table.insert_string(a);
  368. assert(a[0] == 's'); // must be of type string
  369. Alg_parameter_ptr parm = note->parameters->find(attr);
  370. if (parm) return parm->s;
  371. return value;
  372. }
  373. double Alg_event::get_real_value(const char *a, double value)
  374. {
  375. assert(is_note());
  376. assert(a);
  377. Alg_note* note = (Alg_note *) this;
  378. Alg_attribute attr = symbol_table.insert_string(a);
  379. assert(a[0] == 'r'); // must be of type real
  380. Alg_parameter_ptr parm = note->parameters->find(attr);
  381. if (parm) return parm->r;
  382. return value;
  383. }
  384. bool Alg_event::get_logical_value(const char *a, bool value)
  385. {
  386. assert(is_note());
  387. assert(a);
  388. Alg_note* note = (Alg_note *) this;
  389. Alg_attribute attr = symbol_table.insert_string(a);
  390. assert(a[0] == 'l'); // must be of type logical
  391. Alg_parameter_ptr parm = note->parameters->find(attr);
  392. if (parm) return parm->l;
  393. return value;
  394. }
  395. long Alg_event::get_integer_value(const char *a, long value)
  396. {
  397. assert(is_note());
  398. assert(a);
  399. Alg_note* note = (Alg_note *) this;
  400. Alg_attribute attr = symbol_table.insert_string(a);
  401. assert(a[0] == 'i'); // must be of type integer
  402. Alg_parameter_ptr parm = note->parameters->find(attr);
  403. if (parm) return parm->i;
  404. return value;
  405. }
  406. const char *Alg_event::get_atom_value(const char *a, const char *value)
  407. {
  408. assert(is_note());
  409. assert(a);
  410. Alg_note* note = (Alg_note *) this;
  411. Alg_attribute attr = symbol_table.insert_string(a);
  412. assert(a[0] == 'a'); // must be of type atom
  413. Alg_parameter_ptr parm = note->parameters->find(attr);
  414. if (parm) return parm->a;
  415. // if default is a string, convert to an atom (unique
  416. // string in symbol table) and return it
  417. return (value == NULL ? NULL :
  418. symbol_table.insert_string(value));
  419. }
  420. void Alg_event::delete_attribute(const char *a)
  421. {
  422. assert(is_note());
  423. Alg_note* note = (Alg_note *) this;
  424. Alg_parameters::remove_key(&(note->parameters), a);
  425. }
  426. const char *Alg_event::get_attribute()
  427. // Note: this returns a string, not an Alg_attribute
  428. {
  429. assert(is_update());
  430. Alg_update* update = (Alg_update *) this;
  431. return update->parameter.attr_name();
  432. }
  433. char Alg_event::get_update_type()
  434. {
  435. assert(is_update());
  436. Alg_update* update = (Alg_update *) this;
  437. return update->parameter.attr_type();
  438. }
  439. const char *Alg_event::get_string_value()
  440. {
  441. assert(is_update());
  442. Alg_update* update = (Alg_update *) this;
  443. assert(get_update_type() == 's');
  444. return update->parameter.s;
  445. }
  446. double Alg_event::get_real_value()
  447. {
  448. assert(is_update());
  449. Alg_update* update = (Alg_update *) this;
  450. assert(get_update_type() == 'r');
  451. return update->parameter.r;
  452. }
  453. bool Alg_event::get_logical_value()
  454. {
  455. assert(is_update());
  456. Alg_update* update = (Alg_update *) this;
  457. assert(get_update_type() == 'l');
  458. return update->parameter.l;
  459. }
  460. long Alg_event::get_integer_value()
  461. {
  462. assert(is_update());
  463. Alg_update* update = (Alg_update *) this;
  464. assert(get_update_type() == 'i');
  465. return update->parameter.i;
  466. }
  467. const char *Alg_event::get_atom_value()
  468. {
  469. assert(is_update());
  470. Alg_update* update = (Alg_update *) this;
  471. assert(get_update_type() == 'a');
  472. return update->parameter.a;
  473. }
  474. bool Alg_event::overlap(double t, double len, bool all)
  475. {
  476. // event starts within region
  477. if (time >= t && time <= t + len - ALG_EPS)
  478. return true;
  479. if (all && is_note()) {
  480. double dur = ((Alg_note_ptr) this)->dur;
  481. // note overlaps with region
  482. if (time < t && time + dur - ALG_EPS > t)
  483. return true;
  484. }
  485. // does not overlap
  486. return false;
  487. }
  488. Alg_note::Alg_note(Alg_note_ptr note)
  489. {
  490. *this = *note; // copy all fields
  491. // parameters is now a shared pointer. We need to copy the
  492. // parameters
  493. Alg_parameters_ptr next_param_ptr = parameters;
  494. while (next_param_ptr) {
  495. Alg_parameters_ptr new_params = new Alg_parameters(next_param_ptr->next);
  496. new_params->parm.copy(&(next_param_ptr->parm)); // copy the attribute and value
  497. next_param_ptr = new_params->next;
  498. }
  499. }
  500. Alg_note::~Alg_note()
  501. {
  502. while (parameters) {
  503. Alg_parameters_ptr to_delete = parameters;
  504. parameters = parameters->next;
  505. delete to_delete;
  506. }
  507. }
  508. void Alg_note::show()
  509. {
  510. printf("Alg_note: time %g, chan %ld, dur %g, key %ld, "
  511. "pitch %g, loud %g, attributes ",
  512. time, chan, dur, key, pitch, loud);
  513. Alg_parameters_ptr parms = parameters;
  514. while (parms) {
  515. parms->parm.show();
  516. printf(" ");
  517. parms = parms->next;
  518. }
  519. printf("\n");
  520. }
  521. Alg_update::Alg_update(Alg_update_ptr update)
  522. {
  523. *this = *update; // copy all fields
  524. // parameter requires careful copy to possibly duplicate string value:
  525. this->parameter.copy(&(update->parameter));
  526. }
  527. void Alg_update::show()
  528. {
  529. printf("Alg_update: ");
  530. parameter.show();
  531. printf("\n");
  532. }
  533. void Alg_events::expand()
  534. {
  535. maxlen = (maxlen + 5); // extra growth for small sizes
  536. maxlen += (maxlen >> 2); // add 25%
  537. Alg_event_ptr *new_events = new Alg_event_ptr[maxlen];
  538. // now do copy
  539. memcpy(new_events, events, len * sizeof(Alg_event_ptr));
  540. if (events) delete[] events;
  541. events = new_events;
  542. }
  543. void Alg_events::insert(Alg_event_ptr event)
  544. {
  545. if (maxlen <= len) {
  546. expand();
  547. }
  548. // Note: if the new event is the last one, the assignment
  549. // events[i] = event; (below) will never execute, so just
  550. // in case, we do the assignment here. events[len] will
  551. // be replaced during the memmove() operation below if
  552. // this is not the last event.
  553. events[len] = event;
  554. len++;
  555. // find insertion point: (this could be a binary search)
  556. for (int i = 0; i < len; i++) {
  557. if (events[i]->time > event->time) {
  558. // insert event at i
  559. memmove(&events[i + 1], &events[i],
  560. sizeof(Alg_event_ptr) * (len - i - 1));
  561. events[i] = event;
  562. return;
  563. }
  564. }
  565. }
  566. Alg_event_ptr Alg_events::uninsert(long index)
  567. {
  568. assert(0 <= index && index < len);
  569. Alg_event_ptr event = events[index];
  570. //printf("memmove: %x from %x (%d)\n", events + index, events + index + 1,
  571. // sizeof(Alg_event_ptr) * (len - index - 1));
  572. memmove(events + index, events + index + 1,
  573. sizeof(Alg_event_ptr) * (len - index - 1));
  574. len--;
  575. return event;
  576. }
  577. void Alg_events::append(Alg_event_ptr event)
  578. {
  579. if (maxlen <= len) {
  580. expand();
  581. }
  582. events[len++] = event;
  583. // keep track of last note_off time
  584. if (event->is_note()) {
  585. Alg_note_ptr note = (Alg_note_ptr) event;
  586. double note_off = note->time + note->dur;
  587. if (note_off > last_note_off)
  588. last_note_off = note_off;
  589. }
  590. }
  591. Alg_events::~Alg_events()
  592. {
  593. assert(!in_use);
  594. // individual events are not deleted, only the array
  595. if (events) {
  596. delete[] events;
  597. }
  598. }
  599. Alg_event_list::Alg_event_list(Alg_track *owner)
  600. {
  601. events_owner = owner;
  602. sequence_number = owner->sequence_number;
  603. beat_dur = 0.0; real_dur = 0.0; type = 'e';
  604. }
  605. Alg_event_ptr &Alg_event_list::operator [](int i)
  606. {
  607. assert(i >= 0 && i < len);
  608. return events[i];
  609. }
  610. Alg_event_list::~Alg_event_list()
  611. {
  612. // note that the events contained in the list are not destroyed
  613. }
  614. void Alg_event_list::set_start_time(Alg_event *event, double t)
  615. {
  616. // For Alg_event_list, find the owner and do the update there
  617. // For Alg_track, change the time and move the event to the right place
  618. // For Alg_seq, find the track and do the update there
  619. long index, i;
  620. Alg_track_ptr track_ptr;
  621. if (type == 'e') { // this is an Alg_event_list
  622. // make sure the owner has not changed its event set
  623. assert(events_owner &&
  624. sequence_number == events_owner->sequence_number);
  625. // do the update on the owner
  626. events_owner->set_start_time(event, t);
  627. return;
  628. } else if (type == 't') { // this is an Alg_track
  629. // find the event in the track
  630. track_ptr = (Alg_track_ptr) this;
  631. // this should be a binary search since events are in time order
  632. // probably there should be member function to do the search
  633. for (index = 0; index < length(); index++) {
  634. if ((*track_ptr)[index] == event) goto found_event;
  635. }
  636. } else { // type == 's', an Alg_seq
  637. Alg_seq_ptr seq = (Alg_seq_ptr) this;
  638. for (i = 0; i < seq->tracks(); i++) {
  639. track_ptr = seq->track(i);
  640. // if you implemented binary search, you could call it
  641. // instead of this loop too.
  642. for (index = 0; index < track_ptr->length(); index++) {
  643. if ((*track_ptr)[index] == event) goto found_event;
  644. }
  645. }
  646. }
  647. assert(false); // event not found seq or track!
  648. found_event:
  649. // at this point, track[index] == event
  650. // we could be clever and figure out exactly what notes to move
  651. // but it is simpler to just remove the event and reinsert it:
  652. track_ptr->uninsert(index);
  653. event->time = t;
  654. track_ptr->insert(event);
  655. }
  656. void Alg_beats::expand()
  657. {
  658. maxlen = (maxlen + 5); // extra growth for small sizes
  659. maxlen += (maxlen >> 2); // add 25%
  660. Alg_beat_ptr new_beats = new Alg_beat[maxlen];
  661. // now do copy
  662. memcpy(new_beats, beats, len * sizeof(Alg_beat));
  663. if (beats) delete[] beats;
  664. beats = new_beats;
  665. }
  666. void Alg_beats::insert(long i, Alg_beat_ptr beat)
  667. {
  668. assert(i >= 0 && i <= len);
  669. if (maxlen <= len) {
  670. expand();
  671. }
  672. memmove(&beats[i + 1], &beats[i], sizeof(Alg_beat) * (len - i));
  673. memcpy(&beats[i], beat, sizeof(Alg_beat));
  674. len++;
  675. }
  676. Alg_time_map::Alg_time_map(Alg_time_map *map)
  677. {
  678. refcount = 0;
  679. assert(map->beats[0].beat == 0 && map->beats[0].time == 0);
  680. assert(map->beats.len > 0);
  681. // new_beats[0] = map->beats[0];
  682. // this is commented because
  683. // both new_beats[0] and map->beats[0] should be (0, 0)
  684. for (int i = 1; i < map->beats.len; i++) {
  685. beats.insert(i, &map->beats[i]);
  686. }
  687. last_tempo = map->last_tempo;
  688. last_tempo_flag = map->last_tempo_flag;
  689. }
  690. void Alg_time_map::show()
  691. {
  692. printf("Alg_time_map: ");
  693. for (int i = 0; i < beats.len; i++) {
  694. Alg_beat &b = beats[i];
  695. printf("(%g, %g) ", b.time, b.beat);
  696. }
  697. printf("last tempo: %g\n", last_tempo);
  698. }
  699. long Alg_time_map::locate_time(double time)
  700. {
  701. int i = 0;
  702. while ((i < beats.len) && (time > beats[i].time)) {
  703. i++;
  704. }
  705. return i;
  706. }
  707. long Alg_time_map::locate_beat(double beat)
  708. {
  709. int i = 0;
  710. while ((i < beats.len) && (beat > beats[i].beat)) {
  711. i++;
  712. }
  713. return i;
  714. }
  715. double Alg_time_map::beat_to_time(double beat)
  716. {
  717. Alg_beat_ptr mbi;
  718. Alg_beat_ptr mbi1;
  719. if (beat <= 0) {
  720. return beat;
  721. }
  722. int i = locate_beat(beat);
  723. // case 1: beat is between two time/beat pairs
  724. if (0 < i && i < beats.len) {
  725. mbi = &beats[i - 1];
  726. mbi1 = &beats[i];
  727. // case 2: beat is beyond last time/beat pair
  728. } else if (i == beats.len) {
  729. if (last_tempo_flag) {
  730. return beats[i - 1].time +
  731. (beat - beats[i - 1].beat) / last_tempo;
  732. } else if (i == 1) {
  733. return beat * 60.0 / ALG_DEFAULT_BPM;
  734. // so we use that as default allegro tempo too
  735. } else {
  736. mbi = &beats[i - 2];
  737. mbi1 = &beats[i - 1];
  738. }
  739. // case 3: beat is at time 0
  740. } else /* if (i == 0) */ {
  741. return beats[0].time;
  742. }
  743. // whether we extrapolate or interpolate, the math is the same
  744. double time_dif = mbi1->time - mbi->time;
  745. double beat_dif = mbi1->beat - mbi->beat;
  746. return mbi->time + (beat - mbi->beat) * time_dif / beat_dif;
  747. }
  748. double Alg_time_map::time_to_beat(double time)
  749. {
  750. Alg_beat_ptr mbi;
  751. Alg_beat_ptr mbi1;
  752. if (time <= 0.0) return time;
  753. int i = locate_time(time);
  754. if (i == beats.len) {
  755. if (last_tempo_flag) {
  756. return beats[i - 1].beat +
  757. (time - beats[i - 1].time) * last_tempo;
  758. } else if (i == 1) {
  759. return time * (ALG_DEFAULT_BPM / 60.0);
  760. } else {
  761. mbi = &beats[i - 2];
  762. mbi1 = &beats[i - 1];
  763. }
  764. } else {
  765. mbi = &beats[i - 1];
  766. mbi1 = & beats[i];
  767. }
  768. double time_dif = mbi1->time - mbi->time;
  769. double beat_dif = mbi1->beat - mbi->beat;
  770. return mbi->beat + (time - mbi->time) * beat_dif / time_dif;
  771. }
  772. void Alg_time_map::insert_beat(double time, double beat)
  773. {
  774. int i = locate_time(time); // i is insertion point
  775. if (i < beats.len && within(beats[i].time, time, 0.000001)) {
  776. // replace beat if time is already in the map
  777. beats[i].beat = beat;
  778. } else {
  779. Alg_beat point;
  780. point.beat = beat;
  781. point.time = time;
  782. beats.insert(i, &point);
  783. }
  784. // beats[i] contains new beat
  785. // make sure we didn't generate a zero tempo.
  786. // if so, space beats by one microbeat as necessary
  787. long j = i;
  788. if (j == 0) j = 1; // do not adjust beats[0]
  789. while (j < beats.len &&
  790. beats[j - 1].beat + 0.000001 >= beats[j].beat) {
  791. beats[j].beat = beats[j - 1].beat + 0.000001;
  792. j++;
  793. }
  794. }
  795. bool Alg_time_map::insert_tempo(double tempo, double beat)
  796. {
  797. tempo = tempo / 60.0; // convert to beats per second
  798. // change the tempo at the given beat until the next beat event
  799. if (beat < 0) return false;
  800. double time = beat_to_time(beat);
  801. long i = locate_time(time);
  802. if (i >= beats.len || !within(beats[i].time, time, 0.000001)) {
  803. insert_beat(time, beat);
  804. }
  805. // now i is index of beat where tempo will change
  806. if (i == beats.len - 1) {
  807. last_tempo = tempo;
  808. // printf("last_tempo to %g\n", last_tempo);
  809. last_tempo_flag = true;
  810. } else { // adjust all future beats
  811. // compute the difference in beats
  812. double diff = beats[i + 1].beat - beats[i].beat;
  813. // convert beat difference to seconds at new tempo
  814. diff = diff / tempo;
  815. // figure out old time difference:
  816. double old_diff = beats[i + 1].time - time;
  817. // compute difference too
  818. diff = diff - old_diff;
  819. // apply new_diff to score and beats
  820. i++;
  821. while (i < beats.len) {
  822. beats[i].time = beats[i].time + diff;
  823. i++;
  824. }
  825. }
  826. return true;
  827. }
  828. double Alg_time_map::get_tempo(double beat)
  829. {
  830. Alg_beat_ptr mbi;
  831. Alg_beat_ptr mbi1;
  832. // if beat < 0, there is probably an error; return something nice anyway
  833. if (beat < 0) return ALG_DEFAULT_BPM / 60.0;
  834. long i = locate_beat(beat);
  835. // this code is similar to beat_to_time() so far, but we want to get
  836. // beyond beat if possible because we want the tempo FOLLOWING beat
  837. // (Consider the case beat == 0.0)
  838. if (i < beats.len && beat >= beats[i].beat) i++;
  839. // case 1: beat is between two time/beat pairs
  840. if (i < beats.len) {
  841. mbi = &beats[i - 1];
  842. mbi1 = &beats[i];
  843. // case 2: beat is beyond last time/beat pair
  844. } else /* if (i == beats.len) */ {
  845. if (last_tempo_flag) {
  846. return last_tempo;
  847. } else if (i == 1) {
  848. return ALG_DEFAULT_BPM / 60.0;
  849. } else {
  850. mbi = &beats[i - 2];
  851. mbi1 = &beats[i - 1];
  852. }
  853. }
  854. double time_dif = mbi1->time - mbi->time;
  855. double beat_dif = mbi1->beat - mbi->beat;
  856. return beat_dif / time_dif;
  857. }
  858. bool Alg_time_map::set_tempo(double tempo, double start_beat, double end_beat)
  859. {
  860. if (start_beat >= end_beat) return false;
  861. // algorithm: insert a beat event if necessary at start_beat
  862. // and at end_beat
  863. // delete intervening map elements
  864. // change the tempo
  865. insert_beat(beat_to_time(start_beat), start_beat);
  866. insert_beat(beat_to_time(end_beat), end_beat);
  867. long start_x = locate_beat(start_beat) + 1;
  868. long stop_x = locate_beat(end_beat);
  869. while (stop_x < beats.len) {
  870. beats[start_x] = beats[stop_x];
  871. start_x++;
  872. stop_x++;
  873. }
  874. beats.len = start_x; // truncate the map to new length
  875. return insert_tempo(tempo, start_beat);
  876. }
  877. bool Alg_time_map::stretch_region(double b0, double b1, double dur)
  878. {
  879. // find current duration
  880. double t0 = beat_to_time(b0);
  881. double t1 = beat_to_time(b1);
  882. double old_dur = t1 - t0;
  883. if (old_dur <= 0 || dur <= 0) return false;
  884. double scale = dur / old_dur; // larger scale => slower
  885. // insert a beat if necessary at b0 and b1
  886. insert_beat(t0, b0);
  887. insert_beat(t1, b1);
  888. long start_x = locate_beat(b0);
  889. long stop_x = locate_beat(b1);
  890. double orig_time = beats[start_x].time;
  891. double prev_time = orig_time;
  892. for (int i = start_x + 1; i < beats.len; i++) {
  893. double delta = beats[i].time - orig_time;
  894. if (i <= stop_x) { // change tempo to next Alg_beat
  895. delta *= scale;
  896. }
  897. orig_time = beats[i].time;
  898. prev_time += delta;
  899. beats[i].time = prev_time;
  900. }
  901. return true;
  902. }
  903. void Alg_time_map::trim(double start, double end, bool units_are_seconds)
  904. {
  905. // extract the time map from start to end and shift to time zero
  906. // start and end are time in seconds if units_are_seconds is true
  907. int i = 0; // index into beats
  908. int start_index; // index of first breakpoint after start
  909. int count = 1;
  910. double initial_beat = start;
  911. double final_beat = end;
  912. if (units_are_seconds) {
  913. initial_beat = time_to_beat(start);
  914. final_beat = time_to_beat(end);
  915. } else {
  916. start = beat_to_time(initial_beat);
  917. end = beat_to_time(final_beat);
  918. }
  919. while (i < length() && beats[i].time < start) i++;
  920. // now i is index into beats of the first breakpoint after start
  921. // beats[0] is (0,0) and remains that way
  922. // copy beats[start_index] to beats[1], etc.
  923. // skip any beats at or near (start,initial_beat), using count
  924. // to keep track of how many entries there are
  925. start_index = i;
  926. while (i < length() && beats[i].time < end) {
  927. if (beats[i].time - start > ALG_EPS &&
  928. beats[i].beat - initial_beat > ALG_EPS) {
  929. beats[i].time = beats[i].time - start;
  930. beats[i].beat = beats[i].beat - initial_beat;
  931. beats[i - start_index + 1] = beats[i];
  932. count = count + 1;
  933. } else {
  934. start_index = start_index + 1;
  935. }
  936. i = i + 1;
  937. }
  938. // set last tempo data
  939. // we last examined beats[i-1] and copied it to
  940. // beats[i - start_index]. Next tempo should come
  941. // from beats[i] and store in beats[i - start_index + 1]
  942. // case 1: there is at least one breakpoint beyond end
  943. // => interpolate to put a breakpoint at end
  944. // case 2: no more breakpoints => set last tempo data
  945. if (i < length()) {
  946. // we know beats[i].time >= end, so case 1 applies
  947. beats[i - start_index + 1].time = end - start;
  948. beats[i - start_index + 1].beat = final_beat - initial_beat;
  949. count = count + 1;
  950. }
  951. // else we'll just use stored last tempo (if any)
  952. beats.len = count;
  953. }
  954. void Alg_time_map::cut(double start, double len, bool units_are_seconds)
  955. {
  956. // remove portion of time map from start to start + len,
  957. // shifting the tail left by len. start and len are in whatever
  958. // units the score is in. If you cut the time_map as well as cut
  959. // the tracks of the sequence, then sequences will preserve the
  960. // association between tempo changes and events
  961. double end = start + len;
  962. double initial_beat = start;
  963. double final_beat = end;
  964. int i = 0;
  965. if (units_are_seconds) {
  966. initial_beat = time_to_beat(start);
  967. final_beat = time_to_beat(end);
  968. } else {
  969. start = beat_to_time(initial_beat);
  970. end = beat_to_time(final_beat);
  971. len = end - start;
  972. }
  973. double beat_len = final_beat - initial_beat;
  974. while (i < length() && beats[i].time < start - ALG_EPS) {
  975. i = i + 1;
  976. }
  977. // if no beats exist at or after start, just return; nothing to cut
  978. if (i == length()) return;
  979. // now i is index into beats of the first breakpoint on or
  980. // after start, insert (start, initial_beat) in map
  981. if (i < length() && within(beats[i].time, start, ALG_EPS)) {
  982. // perterb time map slightly (within alg_eps) to place
  983. // break point exactly at the start time
  984. beats[i].time = start;
  985. beats[i].beat = initial_beat;
  986. } else {
  987. Alg_beat point(start, initial_beat);
  988. beats.insert(i, &point);
  989. }
  990. // now, we're correct up to beats[i] and beats[i] happens at start.
  991. // find first beat after end so we can start shifting from there
  992. i = i + 1;
  993. int start_index = i;
  994. while (i < length() && beats[i].time < end + ALG_EPS) i++;
  995. // now beats[i] is the next point to be included in beats
  996. // but from i onward, we must shift by (-len, -beat_len)
  997. while (i < length()) {
  998. Alg_beat &b = beats[i];
  999. b.time = b.time - len;
  1000. b.beat = b.beat - beat_len;
  1001. beats[start_index] = b;
  1002. i = i + 1;
  1003. start_index = start_index + 1;
  1004. }
  1005. beats.len = start_index;
  1006. }
  1007. void Alg_time_map::paste(double beat, Alg_track *tr)
  1008. {
  1009. // insert a given time map at a given time and dur (in beats)
  1010. Alg_time_map_ptr from_map = tr->get_time_map();
  1011. // printf("time map paste\nfrom map\n");
  1012. // from_map->show();
  1013. // printf("to map\n");
  1014. // show();
  1015. Alg_beats &from = from_map->beats;
  1016. double time = beat_to_time(beat);
  1017. // Locate the point at which dur occurs
  1018. double dur = tr->get_beat_dur();
  1019. double tr_end_time = from_map->beat_to_time(dur);
  1020. // add offset to make room for insert
  1021. int i = locate_beat(beat);
  1022. while (i < length()) {
  1023. beats[i].beat += dur;
  1024. beats[i].time += tr_end_time;
  1025. i++;
  1026. }
  1027. // printf("after opening up\n");
  1028. // show();
  1029. // insert point at beginning and end of paste
  1030. insert_beat(time, beat);
  1031. // printf("after beginning point insert\n");
  1032. // show();
  1033. // insert_beat(time + tr_end_time, beat + dur);
  1034. // printf("after ending point insert\n");
  1035. // show();
  1036. int j = from_map->locate_beat(dur);
  1037. for (i = 0; i < j; i++) {
  1038. insert_beat(from[i].time + time, // shift by time
  1039. from[i].beat + beat); // and beat
  1040. }
  1041. // printf("after inserts\n");
  1042. show();
  1043. }
  1044. void Alg_time_map::insert_time(double start, double len)
  1045. {
  1046. // find time,beat pair that determines tempo at start
  1047. // compute beat offset = (delta beat / delta time) * len
  1048. // add len,beat offset to each following Alg_beat
  1049. // show();
  1050. int i = locate_time(start); // start <= beats[i].time
  1051. if (beats[i].time == start) i++; // start < beats[i].time
  1052. // case 1: between beats
  1053. if (i > 0 && i < length()) {
  1054. double beat_offset = len * (beats[i].beat - beats[i-1].beat) /
  1055. (beats[i].time - beats[i-1].time);
  1056. while (i < length()) {
  1057. beats[i].beat += beat_offset;
  1058. beats[i].time += len;
  1059. i++;
  1060. }
  1061. } // otherwise, last tempo is in effect; nothing to do
  1062. // printf("time_map AFTER INSERT\n");
  1063. // show();
  1064. }
  1065. void Alg_time_map::insert_beats(double start, double len)
  1066. {
  1067. int i = locate_beat(start); // start <= beats[i].beat
  1068. if (beats[i].beat == start) i++;
  1069. if (i > 0 && i < length()) {
  1070. double time_offset = len * (beats[i].time - beats[i-1].time) /
  1071. (beats[i].beat - beats[i-1].beat);
  1072. while (i < length()) {
  1073. beats[i].time += time_offset;
  1074. beats[i].beat += len;
  1075. i++;
  1076. }
  1077. } // otherwise, last tempo is in effect; nothing to do
  1078. // printf("time_map AFTER INSERT\n");
  1079. // show();
  1080. }
  1081. Alg_track::Alg_track(Alg_time_map *map, bool seconds)
  1082. {
  1083. type = 't';
  1084. time_map = NULL;
  1085. units_are_seconds = seconds;
  1086. set_time_map(map);
  1087. }
  1088. Alg_event_ptr Alg_track::copy_event(Alg_event_ptr event)
  1089. {
  1090. Alg_event *new_event;
  1091. if (event->is_note()) {
  1092. new_event = new Alg_note((Alg_note_ptr) event);
  1093. } else { // update
  1094. new_event = new Alg_update((Alg_update_ptr) event);
  1095. }
  1096. return new_event;
  1097. }
  1098. Alg_track::Alg_track(Alg_track &track)
  1099. {
  1100. type = 't';
  1101. time_map = NULL;
  1102. for (int i = 0; i < track.length(); i++) {
  1103. append(copy_event(track.events[i]));
  1104. }
  1105. set_time_map(track.time_map);
  1106. units_are_seconds = track.units_are_seconds;
  1107. }
  1108. Alg_track::Alg_track(Alg_event_list_ref event_list, Alg_time_map_ptr map,
  1109. bool units_are_seconds)
  1110. {
  1111. type = 't';
  1112. time_map = NULL;
  1113. for (int i = 0; i < event_list.length(); i++) {
  1114. append(copy_event(event_list[i]));
  1115. }
  1116. set_time_map(map);
  1117. this->units_are_seconds = units_are_seconds;
  1118. }
  1119. void Alg_track::serialize(void **buffer, long *bytes)
  1120. {
  1121. // first determine whether this is a seq or a track.
  1122. // if it is a seq, then we will write the time map and a set of tracks
  1123. // if it is a track, we just write the track data and not the time map
  1124. //
  1125. // The code will align doubles on ALIGN boundaries, and longs and
  1126. // floats are aligned to multiples of 4 bytes.
  1127. //
  1128. // The format for a seq is:
  1129. // 'ALGS' -- indicates that this is a sequence
  1130. // long length of all seq data in bytes starting with 'ALGS'
  1131. // long channel_offset_per_track
  1132. // long units_are_seconds
  1133. // time_map:
  1134. // double last_tempo
  1135. // long last_tempo_flag
  1136. // long len -- number of tempo changes
  1137. // for each tempo change (Alg_beat):
  1138. // double time
  1139. // double beat
  1140. // time_sigs:
  1141. // long len -- number of time_sigs
  1142. // long pad
  1143. // for each time signature:
  1144. // double beat
  1145. // double num
  1146. // double den
  1147. // tracks:
  1148. // long len -- number of tracks
  1149. // long pad
  1150. // for each track:
  1151. // 'ALGT' -- indicates this is a track
  1152. // long length of all track data in bytes starting with 'ALGT'
  1153. // long units_are_seconds
  1154. // double beat_dur
  1155. // double real_dur
  1156. // long len -- number of events
  1157. // for each event:
  1158. // long selected
  1159. // long type
  1160. // long key
  1161. // long channel
  1162. // double time
  1163. // if this is a note:
  1164. // double pitch
  1165. // double dur
  1166. // double loud
  1167. // long len -- number of parameters
  1168. // for each parameter:
  1169. // char attribute[] with zero pad to ALIGN
  1170. // one of the following, depending on type:
  1171. // double r
  1172. // char s[] terminated by zero
  1173. // long i
  1174. // long l
  1175. // char a[] terminated by zero
  1176. // zero pad to ALIGN
  1177. // else if this is an update
  1178. // (same representation as parameter above)
  1179. // zero pad to ALIGN
  1180. //
  1181. // The format for a track is given within the Seq format above
  1182. assert(get_type() == 't');
  1183. ser_write_buf.init_for_write();
  1184. serialize_track();
  1185. *buffer = ser_write_buf.to_heap(bytes);
  1186. }
  1187. void Alg_seq::serialize(void **buffer, long *bytes)
  1188. {
  1189. assert(get_type() == 's');
  1190. ser_write_buf.init_for_write();
  1191. serialize_seq();
  1192. *buffer = ser_write_buf.to_heap(bytes);
  1193. }
  1194. void Serial_write_buffer::check_buffer(long needed)
  1195. {
  1196. if (len < (ptr - buffer) + needed) { // do we need more space?
  1197. long new_len = len * 2; // exponential growth is important
  1198. // initially, length is zero, so bump new_len to a starting value
  1199. if (new_len == 0) new_len = 1024;
  1200. // make sure new_len is as big as needed
  1201. if (needed > new_len) new_len = needed;
  1202. char *new_buffer = new char[new_len]; // allocate space
  1203. ptr = new_buffer + (ptr - buffer); // relocate ptr to new buffer
  1204. if (len > 0) { // we had a buffer already
  1205. memcpy(new_buffer, buffer, len); // copy from old buffer
  1206. delete buffer; // free old buffer
  1207. }
  1208. buffer = new_buffer; // update buffer information
  1209. len = new_len;
  1210. }
  1211. }
  1212. void Alg_seq::serialize_seq()
  1213. {
  1214. int i; // loop counters
  1215. // we can easily compute how much buffer space we need until we
  1216. // get to tracks, so expand at least that much
  1217. long needed = 64 + 16 * time_map->beats.len + 24 * time_sig.length();
  1218. ser_write_buf.check_buffer(needed);
  1219. ser_write_buf.set_char('A');
  1220. ser_write_buf.set_char('L');
  1221. ser_write_buf.set_char('G');
  1222. ser_write_buf.set_char('S');
  1223. long length_offset = ser_write_buf.get_posn();
  1224. ser_write_buf.set_int32(0); // leave room to come back and write length
  1225. ser_write_buf.set_int32(channel_offset_per_track);
  1226. ser_write_buf.set_int32(units_are_seconds);
  1227. ser_write_buf.set_double(beat_dur);
  1228. ser_write_buf.set_double(real_dur);
  1229. ser_write_buf.set_double(time_map->last_tempo);
  1230. ser_write_buf.set_int32(time_map->last_tempo_flag);
  1231. ser_write_buf.set_int32(time_map->beats.len);
  1232. for (i = 0; i < time_map->beats.len; i++) {
  1233. ser_write_buf.set_double(time_map->beats[i].time);
  1234. ser_write_buf.set_double(time_map->beats[i].beat);
  1235. }
  1236. ser_write_buf.set_int32(time_sig.length());
  1237. ser_write_buf.pad();
  1238. for (i = 0; i < time_sig.length(); i++) {
  1239. ser_write_buf.set_double(time_sig[i].beat);
  1240. ser_write_buf.set_double(time_sig[i].num);
  1241. ser_write_buf.set_double(time_sig[i].den);
  1242. }
  1243. ser_write_buf.set_int32(tracks());
  1244. ser_write_buf.pad();
  1245. for (i = 0; i < tracks(); i++) {
  1246. track(i)->serialize_track();
  1247. }
  1248. // do not include ALGS, include padding at end
  1249. ser_write_buf.store_long(length_offset, ser_write_buf.get_posn() - length_offset);
  1250. }
  1251. void Alg_track::serialize_track()
  1252. {
  1253. // to simplify the code, copy from parameter addresses to locals
  1254. int j;
  1255. ser_write_buf.check_buffer(32);
  1256. ser_write_buf.set_char('A');
  1257. ser_write_buf.set_char('L');
  1258. ser_write_buf.set_char('G');
  1259. ser_write_buf.set_char('T');
  1260. long length_offset = ser_write_buf.get_posn(); // save location for track length
  1261. ser_write_buf.set_int32(0); // room to write track length
  1262. ser_write_buf.set_int32(units_are_seconds);
  1263. ser_write_buf.set_double(beat_dur);
  1264. ser_write_buf.set_double(real_dur);
  1265. ser_write_buf.set_int32(len);
  1266. for (j = 0; j < len; j++) {
  1267. ser_write_buf.check_buffer(24);
  1268. Alg_event *event = (*this)[j];
  1269. ser_write_buf.set_int32(event->get_selected());
  1270. ser_write_buf.set_int32(event->get_type());
  1271. ser_write_buf.set_int32(event->get_identifier());
  1272. ser_write_buf.set_int32(event->chan);
  1273. ser_write_buf.set_double(event->time);
  1274. if (event->is_note()) {
  1275. ser_write_buf.check_buffer(20);
  1276. Alg_note *note = (Alg_note *) event;
  1277. ser_write_buf.set_float(note->pitch);
  1278. ser_write_buf.set_float(note->loud);
  1279. ser_write_buf.set_double(note->dur);
  1280. long parm_num_offset = ser_write_buf.get_posn();
  1281. long parm_num = 0;
  1282. ser_write_buf.set_int32(0); // placeholder for no. parameters
  1283. Alg_parameters_ptr parms = note->parameters;
  1284. while (parms) {
  1285. serialize_parameter(&(parms->parm));
  1286. parms = parms->next;
  1287. parm_num++;
  1288. }
  1289. ser_write_buf.store_long(parm_num_offset, parm_num);
  1290. } else {
  1291. assert(event->is_update());
  1292. Alg_update *update = (Alg_update *) event;
  1293. serialize_parameter(&(update->parameter));
  1294. }
  1295. ser_write_buf.check_buffer(7); // maximum padding possible
  1296. ser_write_buf.pad();
  1297. }
  1298. // write length, not including ALGT, including padding at end
  1299. ser_write_buf.store_long(length_offset, ser_write_buf.get_posn() - length_offset);
  1300. }
  1301. void Alg_track::serialize_parameter(Alg_parameter *parm)
  1302. {
  1303. // add eight to account for name + zero end-of-string and the
  1304. // possibility of adding 7 padding bytes
  1305. long len = strlen(parm->attr_name()) + 8;
  1306. ser_write_buf.check_buffer(len);
  1307. ser_write_buf.set_string(parm->attr_name());
  1308. ser_write_buf.pad();
  1309. switch (parm->attr_type()) {
  1310. case 'r':
  1311. ser_write_buf.check_buffer(8);
  1312. ser_write_buf.set_double(parm->r);
  1313. break;
  1314. case 's':
  1315. ser_write_buf.check_buffer(strlen(parm->s) + 1);
  1316. ser_write_buf.set_string(parm->s);
  1317. break;
  1318. case 'i':
  1319. ser_write_buf.check_buffer(4);
  1320. ser_write_buf.set_int32(parm->i);
  1321. break;
  1322. case 'l':
  1323. ser_write_buf.check_buffer(4);
  1324. ser_write_buf.set_int32(parm->l);
  1325. break;
  1326. case 'a':
  1327. ser_write_buf.check_buffer(strlen(parm->a) + 1);
  1328. ser_write_buf.set_string(parm->a);
  1329. break;
  1330. }
  1331. }
  1332. Alg_track *Alg_track::unserialize(void *buffer, long len)
  1333. {
  1334. assert(len > 8);
  1335. ser_read_buf.init_for_read(buffer, len);
  1336. bool alg = ser_read_buf.get_char() == 'A' &&
  1337. ser_read_buf.get_char() == 'L' &&
  1338. ser_read_buf.get_char() == 'G';
  1339. assert(alg);
  1340. char c = ser_read_buf.get_char();
  1341. if (c == 'S') {
  1342. Alg_seq *seq = new Alg_seq;
  1343. ser_read_buf.unget_chars(4); // undo get_char() of A,L,G,S
  1344. seq->unserialize_seq();
  1345. return seq;
  1346. } else {
  1347. assert(c == 'T');
  1348. Alg_track *track = new Alg_track;
  1349. ser_read_buf.unget_chars(4); // undo get_char() of A,L,G,T
  1350. track->unserialize_track();
  1351. return track;
  1352. }
  1353. }
  1354. #pragma warning(disable: 4800) // long to bool performance warning
  1355. /* Note: this Alg_seq must have a default initialized Alg_time_map.
  1356. * It will be filled in with data from the ser_read_buf buffer.
  1357. */
  1358. void Alg_seq::unserialize_seq()
  1359. {
  1360. ser_read_buf.check_input_buffer(48);
  1361. bool algs = (ser_read_buf.get_char() == 'A') &&
  1362. (ser_read_buf.get_char() == 'L') &&
  1363. (ser_read_buf.get_char() == 'G') &&
  1364. (ser_read_buf.get_char() == 'S');
  1365. assert(algs);
  1366. long len = ser_read_buf.get_int32();
  1367. assert(ser_read_buf.get_len() >= len);
  1368. channel_offset_per_track = ser_read_buf.get_int32();
  1369. units_are_seconds = ser_read_buf.get_int32() != 0;
  1370. beat_dur = ser_read_buf.get_double();
  1371. real_dur = ser_read_buf.get_double();
  1372. // no need to allocate an Alg_time_map since it's done during initialization
  1373. time_map->last_tempo = ser_read_buf.get_double();
  1374. time_map->last_tempo_flag = ser_read_buf.get_int32() != 0;
  1375. long beats = ser_read_buf.get_int32();
  1376. ser_read_buf.check_input_buffer(beats * 16 + 4);
  1377. int i;
  1378. for (i = 0; i < beats; i++) {
  1379. double time = ser_read_buf.get_double();
  1380. double beat = ser_read_buf.get_double();
  1381. time_map->insert_beat(time, beat);
  1382. // printf("time_map: %g, %g\n", time, beat);
  1383. }
  1384. long time_sig_len = ser_read_buf.get_int32();
  1385. ser_read_buf.get_pad();
  1386. ser_read_buf.check_input_buffer(time_sig_len * 24 + 8);
  1387. for (i = 0; i < time_sig_len; i++) {
  1388. double beat = ser_read_buf.get_double();
  1389. double num = ser_read_buf.get_double();
  1390. double den = ser_read_buf.get_double();
  1391. time_sig.insert(beat, num, den);
  1392. }
  1393. long tracks_num = ser_read_buf.get_int32();
  1394. ser_read_buf.get_pad();
  1395. add_track(tracks_num - 1); // create tracks_num tracks
  1396. for (i = 0; i < tracks_num; i++) {
  1397. track(i)->unserialize_track();
  1398. }
  1399. // assume seq started at beginning of buffer. len measures
  1400. // bytes after 'ALGS' header, so add 4 bytes and compare to
  1401. // current buffer position -- they should agree
  1402. assert(ser_read_buf.get_posn() == len + 4);
  1403. }
  1404. void Alg_track::unserialize_track()
  1405. {
  1406. ser_read_buf.check_input_buffer(32);
  1407. bool algt = (ser_read_buf.get_char() == 'A') &&
  1408. (ser_read_buf.get_char() == 'L') &&
  1409. (ser_read_buf.get_char() == 'G') &&
  1410. (ser_read_buf.get_char() == 'T');
  1411. assert(algt);
  1412. long offset = ser_read_buf.get_posn(); // stored length does not include 'ALGT'
  1413. long bytes = ser_read_buf.get_int32();
  1414. assert(bytes <= ser_read_buf.get_len() - offset);
  1415. units_are_seconds = (bool) ser_read_buf.get_int32();
  1416. beat_dur = ser_read_buf.get_double();
  1417. real_dur = ser_read_buf.get_double();
  1418. int event_count = ser_read_buf.get_int32();
  1419. for (int i = 0; i < event_count; i++) {
  1420. ser_read_buf.check_input_buffer(24);
  1421. long selected = ser_read_buf.get_int32();
  1422. char type = (char) ser_read_buf.get_int32();
  1423. long key = ser_read_buf.get_int32();
  1424. long channel = ser_read_buf.get_int32();
  1425. double time = ser_read_buf.get_double();
  1426. if (type == 'n') {
  1427. ser_read_buf.check_input_buffer(20);
  1428. float pitch = ser_read_buf.get_float();
  1429. float loud = ser_read_buf.get_float();
  1430. double dur = ser_read_buf.get_double();
  1431. Alg_note *note =
  1432. create_note(time, channel, key, pitch, loud, dur);
  1433. note->set_selected(selected != 0);
  1434. long param_num = ser_read_buf.get_int32();
  1435. int j;
  1436. // this builds a list of parameters in the correct order
  1437. // (although order shouldn't matter)
  1438. Alg_parameters_ptr *list = &note->parameters;
  1439. for (j = 0; j < param_num; j++) {
  1440. *list = new Alg_parameters(NULL);
  1441. unserialize_parameter(&((*list)->parm));
  1442. list = &((*list)->next);
  1443. }
  1444. append(note);
  1445. } else {
  1446. assert(type == 'u');
  1447. Alg_update *update = create_update(time, channel, key);
  1448. update->set_selected(selected != 0);
  1449. unserialize_parameter(&(update->parameter));
  1450. append(update);
  1451. }
  1452. ser_read_buf.get_pad();
  1453. }
  1454. assert(offset + bytes == ser_read_buf.get_posn());
  1455. }
  1456. void Alg_track::unserialize_parameter(Alg_parameter_ptr parm_ptr)
  1457. {
  1458. Alg_attribute attr = ser_read_buf.get_string();
  1459. parm_ptr->attr = symbol_table.insert_string(attr);
  1460. switch (parm_ptr->attr_type()) {
  1461. case 'r':
  1462. ser_read_buf.check_input_buffer(8);
  1463. parm_ptr->r = ser_read_buf.get_double();
  1464. break;
  1465. case 's':
  1466. parm_ptr->s = heapify(ser_read_buf.get_string());
  1467. break;
  1468. case 'i':
  1469. ser_read_buf.check_input_buffer(4);
  1470. parm_ptr->i = ser_read_buf.get_int32();
  1471. break;
  1472. case

Large files files are truncated, but you can click here to view the full file